Salome HOME
Merge from V6_main 11/02/2013
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2012  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.
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 "MEDCouplingUMesh.hxx"
22 #include "MEDCouplingMemArray.txx"
23 #include "MEDCouplingFieldDouble.hxx"
24 #include "CellModel.hxx"
25 #include "VolSurfUser.txx"
26 #include "InterpolationUtils.hxx"
27 #include "PointLocatorAlgos.txx"
28 #include "BBTree.txx"
29 #include "SplitterTetra.hxx"
30 #include "DirectedBoundingBox.hxx"
31 #include "InterpKernelMeshQuality.hxx"
32 #include "InterpKernelCellSimplify.hxx"
33 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
34 #include "MEDCouplingAutoRefCountObjectPtr.hxx"
35 #include "InterpKernelAutoPtr.hxx"
36 #include "InterpKernelGeo2DNode.hxx"
37 #include "InterpKernelGeo2DEdgeLin.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
40
41 #include <sstream>
42 #include <fstream>
43 #include <numeric>
44 #include <cstring>
45 #include <limits>
46 #include <list>
47
48 using namespace ParaMEDMEM;
49
50 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
51
52 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
53
54 MEDCouplingUMesh *MEDCouplingUMesh::New()
55 {
56   return new MEDCouplingUMesh;
57 }
58
59 MEDCouplingUMesh *MEDCouplingUMesh::New(const char *meshName, int meshDim)
60 {
61   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
62   ret->setName(meshName);
63   ret->setMeshDimension(meshDim);
64   return ret;
65 }
66
67 MEDCouplingMesh *MEDCouplingUMesh::deepCpy() const
68 {
69   return clone(true);
70 }
71
72 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
73 {
74   return new MEDCouplingUMesh(*this,recDeepCpy);
75 }
76
77 std::size_t MEDCouplingUMesh::getHeapMemorySize() const
78 {
79   std::size_t ret=0;
80   if(_nodal_connec)
81     ret+=_nodal_connec->getHeapMemorySize();
82   if(_nodal_connec_index)
83     ret+=_nodal_connec_index->getHeapMemorySize();
84   return MEDCouplingPointSet::getHeapMemorySize()+ret;
85 }
86
87 void MEDCouplingUMesh::updateTime() const
88 {
89   MEDCouplingPointSet::updateTime();
90   if(_nodal_connec)
91     {
92       updateTimeWith(*_nodal_connec);
93     }
94   if(_nodal_connec_index)
95     {
96       updateTimeWith(*_nodal_connec_index);
97     }
98 }
99
100 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
101 {
102 }
103
104 /*!
105  * This method checks that this is correctly designed. For example le coordinates are set, nodal connectivity.
106  * When this method returns without throwing any exception, 'this' is expected to be writable, exchangeable and to be 
107  * available for most of algorithm. When a mesh has been constructed from scratch it is a good habits to call this method to check
108  * that all is in order in 'this'.
109  */
110 void MEDCouplingUMesh::checkCoherency() const throw(INTERP_KERNEL::Exception)
111 {
112   if(_mesh_dim<-1)
113    throw INTERP_KERNEL::Exception("No mesh dimension specified !");
114   if(_mesh_dim!=-1)
115     MEDCouplingPointSet::checkCoherency();
116   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
117     {
118       if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
119         {
120           std::ostringstream message;
121           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
122           throw INTERP_KERNEL::Exception(message.str().c_str());
123         }
124     }
125   if(_nodal_connec)
126     {
127       if(_nodal_connec->getNumberOfComponents()!=1)
128         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
129       if(_nodal_connec->getInfoOnComponent(0)!="")
130         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
131     }
132   if(_nodal_connec_index)
133     {
134       if(_nodal_connec_index->getNumberOfComponents()!=1)
135         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
136       if(_nodal_connec_index->getInfoOnComponent(0)!="")
137         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
138     }
139 }
140
141 /*!
142  * This method performs deeper checking in 'this' than MEDCouplingUMesh::checkCoherency does.
143  * So this method is more time-consuming. This method checks that nodal connectivity points to valid node ids.
144  * No geometrical aspects are checked here. These aspects are done in MEDCouplingUMesh::checkCoherency2.
145  */
146 void MEDCouplingUMesh::checkCoherency1(double eps) const throw(INTERP_KERNEL::Exception)
147 {
148   checkCoherency();
149   if(_mesh_dim==-1)
150     return ;
151   int meshDim=getMeshDimension();
152   int nbOfNodes=getNumberOfNodes();
153   int nbOfCells=getNumberOfCells();
154   const int *ptr=_nodal_connec->getConstPointer();
155   const int *ptrI=_nodal_connec_index->getConstPointer();
156   for(int i=0;i<nbOfCells;i++)
157     {
158       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
159       if((int)cm.getDimension()!=meshDim)
160         {
161           std::ostringstream oss;
162           oss << "MEDCouplingUMesh::checkCoherency1 : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
163           throw INTERP_KERNEL::Exception(oss.str().c_str());
164         }
165       int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
166       if(!cm.isDynamic())
167         if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
168           {
169             std::ostringstream oss;
170             oss << "MEDCouplingUMesh::checkCoherency1 : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
171             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
172             throw INTERP_KERNEL::Exception(oss.str().c_str());
173           }
174       for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
175         {
176           int nodeId=*w;
177           if(nodeId>=0)
178             {
179               if(nodeId>=nbOfNodes)
180                 {
181                   std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes !";
182                   throw INTERP_KERNEL::Exception(oss.str().c_str());
183                 }
184             }
185           else if(nodeId<-1)
186             {
187               std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #" << nodeId << " in connectivity ! sounds bad !";
188               throw INTERP_KERNEL::Exception(oss.str().c_str());
189             }
190           else
191             {
192               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
193                 {
194                   std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #-1 in connectivity ! sounds bad !";
195                   throw INTERP_KERNEL::Exception(oss.str().c_str());
196                 }
197             }
198         }
199     }
200 }
201
202 void MEDCouplingUMesh::checkCoherency2(double eps) const throw(INTERP_KERNEL::Exception)
203 {
204   checkCoherency1(eps);
205 }
206
207 void MEDCouplingUMesh::setMeshDimension(int meshDim)
208 {
209   if(meshDim<-1)
210     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 !");
211   _mesh_dim=meshDim;
212   declareAsNew();
213 }
214
215 void MEDCouplingUMesh::allocateCells(int nbOfCells)
216 {
217   if(_nodal_connec_index)
218     {
219       _nodal_connec_index->decrRef();
220     }
221   if(_nodal_connec)
222     {
223       _nodal_connec->decrRef();
224     }
225   _nodal_connec_index=DataArrayInt::New();
226   _nodal_connec_index->reserve(nbOfCells+1);
227   _nodal_connec_index->pushBackSilent(0);
228   _nodal_connec=DataArrayInt::New();
229   _nodal_connec->reserve(2*nbOfCells);
230   _types.clear();
231   declareAsNew();
232 }
233
234 /*!
235  * Appends a cell in connectivity array.
236  * @param type type of cell to add.
237  * @param size number of nodes constituting this cell.
238  * @param nodalConnOfCell the connectivity of the cell to add.
239  */
240 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell) throw(INTERP_KERNEL::Exception)
241 {
242   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
243   if(_nodal_connec_index==0)
244     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
245   if((int)cm.getDimension()==_mesh_dim)
246     {
247       if(!cm.isDynamic())
248         if(size!=(int)cm.getNumberOfNodes())
249           {
250             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
251             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
252             throw INTERP_KERNEL::Exception(oss.str().c_str());
253           }
254       int idx=_nodal_connec_index->back();
255       int val=idx+size+1;
256       _nodal_connec_index->pushBackSilent(val);
257       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
258       _types.insert(type);
259     }
260   else
261     {
262       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
263       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
264       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
265       throw INTERP_KERNEL::Exception(oss.str().c_str());
266     }
267 }
268
269 /*!
270  * Method to be called to cloture the insertion of cells using this->insertNextCell.
271  */
272 void MEDCouplingUMesh::finishInsertingCells()
273 {
274   _nodal_connec->pack();
275   _nodal_connec_index->pack();
276   _nodal_connec->declareAsNew();
277   _nodal_connec_index->declareAsNew();
278   updateTime();
279 }
280
281 /*!
282  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
283  * Useful for python users.
284  */
285 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
286 {
287   return new MEDCouplingUMeshCellIterator(this);
288 }
289
290 /*!
291  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
292  * If 'this' is not so that that cells are grouped by geo types this method will throw an exception.
293  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
294  * Useful for python users.
295  */
296 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType() throw(INTERP_KERNEL::Exception)
297 {
298   if(!checkConsecutiveCellTypes())
299     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
300   return new MEDCouplingUMeshCellByTypeEntry(this);
301 }
302
303 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
304 {
305   return _types;
306 }
307
308 /*!
309  * This method is a method that compares 'this' and 'other'.
310  * This method compares \b all attributes, even names and component names.
311  */
312 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const throw(INTERP_KERNEL::Exception)
313 {
314   if(!other)
315     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
316   std::ostringstream oss; oss.precision(15);
317   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
318   if(!otherC)
319     {
320       reason="mesh given in input is not castable in MEDCouplingUMesh !";
321       return false;
322     }
323   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
324     return false;
325   if(_mesh_dim!=otherC->_mesh_dim)
326     {
327       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
328       reason=oss.str();
329       return false;
330     }
331   if(_types!=otherC->_types)
332     {
333       oss << "umesh geometric type mismatch :\nThis geometric types are :";
334       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
335         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
336       oss << "\nOther geometric types are :";
337       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
338         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
339       reason=oss.str();
340       return false;
341     }
342   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
343     if(_nodal_connec==0 || otherC->_nodal_connec==0)
344       {
345         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
346         return false;
347       }
348   if(_nodal_connec!=otherC->_nodal_connec)
349     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
350       {
351         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
352         return false;
353       }
354   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
355     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
356       {
357         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
358         return false;
359       }
360   if(_nodal_connec_index!=otherC->_nodal_connec_index)
361     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
362       {
363         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
364         return false;
365       }
366   return true;
367 }
368
369 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
370 {
371   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
372   if(!otherC)
373     return false;
374   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
375     return false;
376   if(_mesh_dim!=otherC->_mesh_dim)
377     return false;
378   if(_types!=otherC->_types)
379     return false;
380   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
381     if(_nodal_connec==0 || otherC->_nodal_connec==0)
382       return false;
383   if(_nodal_connec!=otherC->_nodal_connec)
384     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
385       return false;
386   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
387     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
388       return false;
389   if(_nodal_connec_index!=otherC->_nodal_connec_index)
390     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
391       return false;
392   return true;
393 }
394
395 /*!
396  * This method looks if 'this' and 'other' are geometrically equivalent that is to say if each cell in 'other' correspond to one cell and only one
397  * in 'this' is found regarding 'prec' parameter and 'cellCompPol' parameter.
398  * 
399  * In case of success cellCor and nodeCor are informed both. 
400  * @param cellCompPol values are described in MEDCouplingUMesh::zipConnectivityTraducer method.
401  * @param cellCor output array giving the correspondance of cells from 'other' to 'this'.
402  * @param nodeCor output array giving the correspondance of nodes from 'other' to 'this'.
403  */
404 void MEDCouplingUMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,
405                                             DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const throw(INTERP_KERNEL::Exception)
406 {
407   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
408   if(!otherC)
409     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Two meshes are not not unstructured !");
410   MEDCouplingMesh::checkFastEquivalWith(other,prec);
411   if(_types!=otherC->_types)
412     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Types are not equal !");
413   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MergeUMeshes(this,otherC);
414   bool areNodesMerged;
415   int newNbOfNodes;
416   int oldNbOfNodes=getNumberOfNodes();
417   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=m->buildPermArrayForMergeNode(prec,oldNbOfNodes,areNodesMerged,newNbOfNodes);
418   //mergeNodes
419   if(!areNodesMerged)
420     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Nodes are incompatible ! ");
421   const int *pt=std::find_if(da->getConstPointer()+oldNbOfNodes,da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),oldNbOfNodes-1));
422   if(pt!=da->getConstPointer()+da->getNbOfElems())
423     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : some nodes in other are not in this !");
424   m->renumberNodes(da->getConstPointer(),newNbOfNodes);
425   //
426   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodeCor2=da->substr(oldNbOfNodes);
427   da=m->mergeNodes(prec,areNodesMerged,newNbOfNodes);
428   
429   //
430   da=m->zipConnectivityTraducer(cellCompPol);
431   int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+getNumberOfCells());
432   pt=std::find_if(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
433   if(pt!=da->getConstPointer()+da->getNbOfElems())
434     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : some cells in other are not in this !");
435   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellCor2=da->selectByTupleId2(getNumberOfCells(),da->getNbOfElems(),1);
436   nodeCor=nodeCor2->isIdentity()?0:nodeCor2.retn();
437   cellCor=cellCor2->isIdentity()?0:cellCor2.retn();
438 }
439
440 /*!
441  * This method looks if 'this' and 'other' are geometrically equivalent that is to say if each cell in 'other' correspond to one cell and only one
442  * in 'this' is found regarding 'prec' parameter and 'cellCompPol' parameter. The difference with MEDCouplingUMesh::checkDeepEquivalWith method is that
443  * coordinates of 'this' and 'other' are expected to be the same. If not an exception will be thrown.
444  * This method is close to MEDCouplingUMesh::areCellsIncludedIn except that this method throws exception !
445  * 
446  * In case of success cellCor are informed both. 
447  * @param cellCompPol values are described in MEDCouplingUMesh::zipConnectivityTraducer method.
448  * @param cellCor output array giving the correspondance of cells from 'other' to 'this'.
449  */
450 void MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,
451                                                        DataArrayInt *&cellCor) const throw(INTERP_KERNEL::Exception)
452 {
453   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
454   if(!otherC)
455     throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : Two meshes are not not unstructured !");
456   MEDCouplingMesh::checkFastEquivalWith(other,prec);
457   if(_types!=otherC->_types)
458     throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : Types are not equal !");
459   if(_coords!=otherC->_coords)
460     throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : meshes do not share the same coordinates ! Use tryToShareSameCoordinates or call checkDeepEquivalWith !");
461   std::vector<const MEDCouplingUMesh *> ms(2);
462   ms[0]=this;
463   ms[1]=otherC;
464   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MergeUMeshesOnSameCoords(ms);
465   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=m->zipConnectivityTraducer(cellCompPol);
466   int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+getNumberOfCells());
467   const int *pt=std::find_if(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
468   if(pt!=da->getConstPointer()+da->getNbOfElems())
469     {
470       throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : some cells in other are not in this !");
471     }
472   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellCor2=da->selectByTupleId2(getNumberOfCells(),da->getNbOfElems(),1);
473   cellCor=cellCor2->isIdentity()?0:cellCor2.retn();
474 }
475
476 /*!
477  * This method checks fastly that 'this' and 'other' are equal. 
478  */
479 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const throw(INTERP_KERNEL::Exception)
480 {
481   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
482   if(!otherC)
483     throw INTERP_KERNEL::Exception("checkFastEquivalWith : Two meshes are not not unstructured !");
484   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
485   int nbOfCells=getNumberOfCells();
486   if(nbOfCells<1)
487     return ;
488   bool status=true;
489   status&=areCellsFrom2MeshEqual(otherC,0,prec);
490   status&=areCellsFrom2MeshEqual(otherC,nbOfCells/2,prec);
491   status&=areCellsFrom2MeshEqual(otherC,nbOfCells-1,prec);
492   if(!status)
493     throw INTERP_KERNEL::Exception("checkFastEquivalWith : Two meshes are not equal because on 3 test cells some difference have been detected !");
494 }
495
496 /*!
497  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
498  * For speed reasons no check of this will be done.
499  */
500 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const throw(INTERP_KERNEL::Exception)
501 {
502   checkFullyDefined();
503   int nbOfNodes=getNumberOfNodes();
504   int *revNodalIndxPtr=new int[nbOfNodes+1];
505   revNodalIndx->useArray(revNodalIndxPtr,true,CPP_DEALLOC,nbOfNodes+1,1);
506   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
507   const int *conn=_nodal_connec->getConstPointer();
508   const int *connIndex=_nodal_connec_index->getConstPointer();
509   int nbOfCells=getNumberOfCells();
510   int nbOfEltsInRevNodal=0;
511   for(int eltId=0;eltId<nbOfCells;eltId++)
512     {
513       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
514       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
515       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
516         if(*iter>=0)//for polyhedrons
517           {
518             nbOfEltsInRevNodal++;
519             revNodalIndxPtr[(*iter)+1]++;
520           }
521     }
522   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
523   int *revNodalPtr=new int[nbOfEltsInRevNodal];
524   revNodal->useArray(revNodalPtr,true,CPP_DEALLOC,nbOfEltsInRevNodal,1);
525   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
526   for(int eltId=0;eltId<nbOfCells;eltId++)
527     {
528       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
529       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
530       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
531         if(*iter>=0)//for polyhedrons
532           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
533     }
534 }
535
536 /// @cond INTERNAL
537
538 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
539 {
540   return id;
541 }
542
543 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
544 {
545   if(!compute)
546     return id+1;
547   else
548     {
549       if(cm.getOrientationStatus(nb,conn1,conn2))
550         return id+1;
551       else
552         return -(id+1);
553     }
554 }
555
556 /// @endcond
557
558 /*!
559  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
560  * For speed reasons no check of this will be done.
561  * Given 'this' with spacedim equal to s and meshdim equal to p, this method returns a new allocated mesh
562  * lying on the same coordinates than 'this' and having a meshdim equal to p-1.
563  * The algorithm to compute this p-1 mesh is the following :
564  * For each cell in 'this' it splits into p-1 elements.
565  *   If this p-1 element does not already exists it is appended to the returned mesh
566  *   If this p-1 element already exists, it is not appended.
567  * This method returns or 4 arrays plus the returned mesh.
568  * 'desc' and 'descIndx' are the descending connectivity. These 2 arrays tell for each cell in 'this', to wich p-1 dimension cell in returned mesh it refers.
569  * For a cell with a cellid c in 'this' it is constituted of cells in [desc+descIndx[c],desc+descIndex[c+1])
570  *
571  * Reversely 'revDesc' and 'revDescIndx' are the reverse descending connectivity. These 2 arrays tell for each cell in returned mesh, to wich cell in 'this' it refers.
572  * For a cell with a cellid d in returned p-1 mesh it is shared by the following cells in 'this' [revDesc+revDescIndx[d],revDesc+revDescIndx[d+1])
573  *
574  * \warning This method returns a mesh whose geometric type order in are \b not sorted.
575  * In view of the MED file writing, a renumbering of cells in returned mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
576  */
577 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const throw(INTERP_KERNEL::Exception)
578 {
579   return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
580 }
581
582 /*!
583  * WARNING this method do the assumption that connectivity lies on the coordinates set.
584  * For speed reasons no check of this will be done.
585  * This method differs from MEDCouplingUMesh::buildDescendingConnectivity method in that 'desc' is in different format.
586  * This method is more precise because it returns in descending connectivity giving the direction. If value is positive the n-1 dim element is taken in the same direction,
587  * if it is in the opposite direction it is retrieved negative. So the problem is for elemt #0 in C convention. That's why this method is the only one that retrieves 
588  * an array in relative "FORTRAN" mode.
589  *
590  * \warning This method returns a mesh whose geometric type order in are \b not sorted.
591  * In view of the MED file writing, a renumbering of cells in returned mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
592  */
593 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const throw(INTERP_KERNEL::Exception)
594 {
595   return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
596 }
597
598 /*!
599  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
600  * For speed reasons no check of this will be done. This method calls MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
601  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities are considered.
602  * The a cell with id 'cellId' its neighbors are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
603  *
604  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
605  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
606  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
607  */
608 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const throw(INTERP_KERNEL::Exception)
609 {
610   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
611   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
612   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
613   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
614   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
615   meshDM1=0;
616   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
617 }
618
619 /*!
620  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm of MEDCouplingUMesh::computeNeighborsOfCells.
621  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is typically the case to extract a set a neighbours,
622  * excluding a set of meshdim-1 cells in input descending connectivity.
623  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx input params are the result of MEDCouplingUMesh::buildDescendingConnectivity.
624  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities are considered.
625  * The a cell with id 'cellId' its neighbors are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
626  *
627  * \param [in] desc descending connectivity array.
628  * \param [in] descIndx descending connectivity index array used to walk through \b desc.
629  * \param [in] revDesc reverse descending connectivity array.
630  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc.
631  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
632  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
633  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
634  */
635 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
636                                                   DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) throw(INTERP_KERNEL::Exception)
637 {
638   if(!desc || !descIndx || !revDesc || !revDescIndx)
639     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
640   const int *descPtr=desc->getConstPointer();
641   const int *descIPtr=descIndx->getConstPointer();
642   const int *revDescPtr=revDesc->getConstPointer();
643   const int *revDescIPtr=revDescIndx->getConstPointer();
644   //
645   int nbCells=descIndx->getNumberOfTuples()-1;
646   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> out0=DataArrayInt::New();
647   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
648   int *out1Ptr=out1->getPointer();
649   *out1Ptr++=0;
650   out0->reserve(desc->getNumberOfTuples());
651   for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
652     {
653       for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
654         {
655           std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
656           s.erase(i);
657           out0->insertAtTheEnd(s.begin(),s.end());
658         }
659       *out1Ptr=out0->getNumberOfTuples();
660     }
661   neighbors=out0.retn();
662   neighborsIndx=out1.retn();
663 }
664
665 /// @cond INTERNAL
666
667 /*!
668  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
669  * For speed reasons no check of this will be done.
670  */
671 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const throw(INTERP_KERNEL::Exception)
672 {
673   checkConnectivityFullyDefined();
674   int nbOfCells=getNumberOfCells();
675   int nbOfNodes=getNumberOfNodes();
676   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
677   int *revNodalIndxPtr=revNodalIndx->getPointer();
678   const int *conn=_nodal_connec->getConstPointer();
679   const int *connIndex=_nodal_connec_index->getConstPointer();
680   std::string name="Mesh constituent of "; name+=getName();
681   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name.c_str(),getMeshDimension()-1);
682   ret->setCoords(getCoords());
683   ret->allocateCells(2*nbOfCells);
684   descIndx->alloc(nbOfCells+1,1);
685   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
686   int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
687   for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
688     {
689       int pos=connIndex[eltId];
690       int posP1=connIndex[eltId+1];
691       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
692       unsigned nbOfSons=cm.getNumberOfSons2(conn+pos+1,posP1-pos-1);
693       INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
694       for(unsigned i=0;i<nbOfSons;i++)
695         {
696           INTERP_KERNEL::NormalizedCellType cmsId;
697           unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
698           for(unsigned k=0;k<nbOfNodesSon;k++)
699             if(tmp[k]>=0)
700               revNodalIndxPtr[tmp[k]+1]++;
701           ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
702           revDesc2->pushBackSilent(eltId);
703         }
704       descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
705     }
706   int nbOfCellsM1=ret->getNumberOfCells();
707   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
708   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
709   std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
710   int *revNodalPtr=revNodal->getPointer();
711   const int *connM1=ret->getNodalConnectivity()->getConstPointer();
712   const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
713   for(int eltId=0;eltId<nbOfCellsM1;eltId++)
714     {
715       const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
716       const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
717       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
718         if(*iter>=0)//for polyhedrons
719           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
720     }
721   //
722   DataArrayInt *commonCells=0,*commonCellsI=0;
723   FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
724   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
725   const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
726   int newNbOfCellsM1=-1;
727   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2nM1=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(nbOfCellsM1,commonCells->begin(),
728                                                                                                             commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
729   std::vector<bool> isImpacted(nbOfCellsM1,false);
730   for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
731     for(int work2=work[0];work2!=work[1];work2++)
732       isImpacted[commonCellsPtr[work2]]=true;
733   const int *o2nM1Ptr=o2nM1->getConstPointer();
734   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
735   const int *n2oM1Ptr=n2oM1->getConstPointer();
736   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
737   ret2->copyTinyInfoFrom(this);
738   desc->alloc(descIndx->back(),1);
739   int *descPtr=desc->getPointer();
740   const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
741   for(int i=0;i<nbOfCellsM1;i++,descPtr++)
742     {
743       if(!isImpacted[i])
744         *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
745       else
746         {
747           if(i!=n2oM1Ptr[o2nM1Ptr[i]])
748             {
749               const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
750               *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
751             }
752           else
753             *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
754         }
755     }
756   revDesc->reserve(newNbOfCellsM1);
757   revDescIndx->alloc(newNbOfCellsM1+1,1);
758   int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
759   const int *revDesc2Ptr=revDesc2->getConstPointer();
760   for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
761     {
762       int oldCellIdM1=n2oM1Ptr[i];
763       if(!isImpacted[oldCellIdM1])
764         {
765           revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
766           revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
767         }
768       else
769         {
770           for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
771             revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
772           revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
773           commonCellsIPtr++;
774         }
775     }
776   //
777   return ret2.retn();
778 }
779
780 struct MEDCouplingAccVisit
781 {
782   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
783   int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
784   int _new_nb_of_nodes;
785 };
786
787 /// @endcond
788
789
790 /*!
791  * This method convert cell with ids in ['cellIdsToConvertBg','cellIdsToConvertEnd') into 'this' into dynamic types without changing geometry.
792  * That is to say if 'this' is a 2D, mesh after the invocation of this method it will contain only polygons.
793  * If 'this' is a 3D mesh after the invocation of this method it will contain only polyhedra.
794  * If mesh dimension is not in [2,3] an exception is thrown.
795  * Of course pay attention that the resulting mesh is slower than previous one.
796  * If in ['cellIdsToConvertBg','cellIdsToConvertEnd') there is a cell id not in [0,'this->getNumberOfCells()') an exception will be thrown.
797  * In this case if meshDim==2 the mesh is still valid and only cells treated before throw will be converted into polygon.
798  * If mesh==3, after throw the mesh is \b unconsistent !
799  * This method is above all designed to test more extensively algorithms able to deal with polygons/polyhedra.
800  * 
801  * \warning This method modifies can modify significantly the geometric type order in \a this.
802  * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
803  */
804 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
805 {
806   checkFullyDefined();
807   int dim=getMeshDimension();
808   if(dim<2 || dim>3)
809     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
810   int nbOfCells=getNumberOfCells();
811   if(dim==2)
812     {
813       const int *connIndex=_nodal_connec_index->getConstPointer();
814       int *conn=_nodal_connec->getPointer();
815       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
816         {
817           if(*iter>=0 && *iter<nbOfCells)
818             {
819               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
820               if(!cm.isDynamic())
821                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
822               else
823                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
824             }
825           else
826             {
827               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
828               oss << " in range [0," << nbOfCells << ") !";
829               throw INTERP_KERNEL::Exception(oss.str().c_str());
830             }
831         }
832     }
833   else
834     {
835       int *connIndex=_nodal_connec_index->getPointer();
836       int connIndexLgth=_nodal_connec_index->getNbOfElems();
837       const int *connOld=_nodal_connec->getConstPointer();
838       int connOldLgth=_nodal_connec->getNbOfElems();
839       std::vector<int> connNew(connOld,connOld+connOldLgth);
840       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
841         {
842           if(*iter>=0 && *iter<nbOfCells)
843             {
844               int pos=connIndex[*iter];
845               int posP1=connIndex[(*iter)+1];
846               int lgthOld=posP1-pos-1;
847               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connNew[pos]);
848               connNew[pos]=INTERP_KERNEL::NORM_POLYHED;
849               unsigned nbOfFaces=cm.getNumberOfSons2(&connNew[pos+1],lgthOld);
850               int *tmp=new int[nbOfFaces*lgthOld];
851               int *work=tmp;
852               for(int j=0;j<(int)nbOfFaces;j++)
853                 {
854                   INTERP_KERNEL::NormalizedCellType type;
855                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,&connNew[pos+1],lgthOld,work,type);
856                   work+=offset;
857                   *work++=-1;
858                 }
859               std::size_t newLgth=std::distance(tmp,work)-1;
860               std::size_t delta=newLgth-lgthOld;
861               std::transform(connIndex+(*iter)+1,connIndex+connIndexLgth,connIndex+(*iter)+1,std::bind2nd(std::plus<int>(),delta));
862               connNew.insert(connNew.begin()+posP1,tmp+lgthOld,tmp+newLgth);
863               std::copy(tmp,tmp+lgthOld,connNew.begin()+pos+1);
864               delete [] tmp;
865             }
866           else
867             {
868               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
869               oss << " in range [0," << nbOfCells << ") !";
870               throw INTERP_KERNEL::Exception(oss.str().c_str());
871             }
872         }
873       _nodal_connec->alloc((int)connNew.size(),1);
874       int *newConnPtr=_nodal_connec->getPointer();
875       std::copy(connNew.begin(),connNew.end(),newConnPtr);
876     }
877   computeTypes();
878 }
879
880 /*!
881  * This method converts all cells into poly type if possible.
882  * This method is purely for userfriendliness.
883  * As this method can be costly in Memory, no optimization is done to avoid construction of useless vector.
884  */
885 void MEDCouplingUMesh::convertAllToPoly()
886 {
887   int nbOfCells=getNumberOfCells();
888   std::vector<int> cellIds(nbOfCells);
889   for(int i=0;i<nbOfCells;i++)
890     cellIds[i]=i;
891   convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
892 }
893
894 /*!
895  * This method expects that 'this' has a spacedim equal to 3 and a mesh dimension equal to 3 too, if not an exception will be thrown.
896  * This method work only on cells with type NORM_POLYHED, all other cells with different type, are remains unchanged.
897  * For such polyhedra, they are expected to have only 1 face (containing 2 faces in opposition), having 2*n number of nodes (n nodes on
898  * each 2 faces hidden in the single face of polyhedron).
899  * The first face is expected to be right oriented because all faces of this polyhedron will be deduced.
900  * When called 'this' is an invalid mesh on MED sense. This method will correct that for polyhedra.
901  * In case of presence of polyhedron that has not the extruded aspect (2 faces with the same number of nodes) an exception is thrown and 'this'
902  * remains unchanged.
903  * This method is usefull only for users that wants to build extruded unstructured mesh.
904  * This method is a convenient one that avoids boring polyhedra setting during insertNextCell process.
905  * In case of success, 'this' has be corrected contains the same number of cells and is valid in MED sense.
906  */
907 void MEDCouplingUMesh::convertExtrudedPolyhedra() throw(INTERP_KERNEL::Exception)
908 {
909   checkFullyDefined();
910   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
911     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
912   int nbOfCells=getNumberOfCells();
913   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newCi=DataArrayInt::New();
914   newCi->alloc(nbOfCells+1,1);
915   int *newci=newCi->getPointer();
916   const int *ci=_nodal_connec_index->getConstPointer();
917   const int *c=_nodal_connec->getConstPointer();
918   newci[0]=0;
919   for(int i=0;i<nbOfCells;i++)
920     {
921       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
922       if(type==INTERP_KERNEL::NORM_POLYHED)
923         {
924           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
925             {
926               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
927               throw INTERP_KERNEL::Exception(oss.str().c_str());
928             }
929           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
930           if(n2%2!=0)
931             {
932               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
933               throw INTERP_KERNEL::Exception(oss.str().c_str());
934             }
935           int n1=(int)(n2/2);
936           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
937         }
938       else
939         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
940     }
941   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newC=DataArrayInt::New();
942   newC->alloc(newci[nbOfCells],1);
943   int *newc=newC->getPointer();
944   for(int i=0;i<nbOfCells;i++)
945     {
946       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
947       if(type==INTERP_KERNEL::NORM_POLYHED)
948         {
949           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
950           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
951           *newc++=-1;
952           for(std::size_t j=0;j<n1;j++)
953             {
954               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
955               newc[n1+5*j]=-1;
956               newc[n1+5*j+1]=c[ci[i]+1+j];
957               newc[n1+5*j+2]=c[ci[i]+1+(j+1)%n1];
958               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
959               newc[n1+5*j+4]=c[ci[i]+1+j+n1];
960             }
961           newc+=n1*6;
962         }
963       else
964         newc=std::copy(c+ci[i],c+ci[i+1],newc);
965     }
966   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
967   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
968 }
969
970 /*!
971  * This method is the opposite of ParaMEDMEM::MEDCouplingUMesh::convertToPolyTypes method.
972  * The aim is to take all polygons or polyhedrons cell and to try to traduce them into classical cells.
973  *
974  *  \return If true at least one cell has been unpolyzed.
975             \n If false has been returned the nodal connectivity of \a this has **not** been altered and \a this has remains unchanged.
976  *
977  * \warning This method modifies can modify significantly the geometric type order in \a this.
978  * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
979  */
980 bool MEDCouplingUMesh::unPolyze()
981 {
982   checkFullyDefined();
983   int mdim=getMeshDimension();
984   if(mdim<0)
985     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
986   if(mdim<=1)
987     return false;
988   int nbOfCells=getNumberOfCells();
989   if(nbOfCells<1)
990     return false;
991   int initMeshLgth=getMeshLength();
992   int *conn=_nodal_connec->getPointer();
993   int *index=_nodal_connec_index->getPointer();
994   int posOfCurCell=0;
995   int newPos=0;
996   int lgthOfCurCell;
997   bool ret=false;
998   for(int i=0;i<nbOfCells;i++)
999     {
1000       lgthOfCurCell=index[i+1]-posOfCurCell;
1001       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1002       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1003       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1004       int newLgth;
1005       if(cm.isDynamic())
1006         {
1007           switch(cm.getDimension())
1008             {
1009             case 2:
1010               {
1011                 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1012                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1013                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1014                 break;
1015               }
1016             case 3:
1017               {
1018                 int nbOfFaces,lgthOfPolyhConn;
1019                 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1020                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1021                 break;
1022               }
1023             case 1:
1024               {
1025                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1026                 break;
1027               }
1028             }
1029           ret=ret || (newType!=type);
1030           conn[newPos]=newType;
1031           newPos+=newLgth+1;
1032           posOfCurCell=index[i+1];
1033           index[i+1]=newPos;
1034         }
1035       else
1036         {
1037           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1038           newPos+=lgthOfCurCell;
1039           posOfCurCell+=lgthOfCurCell;
1040           index[i+1]=newPos;
1041         }
1042     }
1043   if(newPos!=initMeshLgth)
1044     _nodal_connec->reAlloc(newPos);
1045   if(ret)
1046     computeTypes();
1047   return ret;
1048 }
1049
1050 /*!
1051  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1052  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1053  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. 
1054  *
1055  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal 
1056  *             precision.
1057  */
1058 void MEDCouplingUMesh::simplifyPolyhedra(double eps) throw(INTERP_KERNEL::Exception)
1059 {
1060   checkFullyDefined();
1061   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1062     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1063   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coords=getCoords()->deepCpy();
1064   coords->recenterForMaxPrecision(eps);
1065   //
1066   int nbOfCells=getNumberOfCells();
1067   const int *conn=_nodal_connec->getConstPointer();
1068   const int *index=_nodal_connec_index->getConstPointer();
1069   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connINew=DataArrayInt::New();
1070   connINew->alloc(nbOfCells+1,1);
1071   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1072   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1073   bool changed=false;
1074   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1075     {
1076       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1077         {
1078           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1079           changed=true;
1080         }
1081       else
1082         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1083       *connINewPtr=connNew->getNumberOfTuples();
1084     }
1085   if(changed)
1086     setConnectivity(connNew,connINew,false);
1087 }
1088
1089 /*!
1090  * This method returns all node ids used in \b this. The data array returned has to be dealt by the caller.
1091  * The returned node ids are sortes ascendingly. This method is closed to MEDCouplingUMesh::getNodeIdsInUse except
1092  * the format of returned DataArrayInt instance.
1093  * 
1094  * @return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1095  * \sa MEDCouplingUMesh::getNodeIdsInUse
1096  */
1097 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const throw(INTERP_KERNEL::Exception)
1098 {
1099   checkConnectivityFullyDefined();
1100   int nbOfCells=getNumberOfCells();
1101   const int *connIndex=_nodal_connec_index->getConstPointer();
1102   const int *conn=_nodal_connec->getConstPointer();
1103   const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1104   int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1105   std::vector<bool> retS(maxElt,false);
1106   for(int i=0;i<nbOfCells;i++)
1107     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1108       if(conn[j]>=0)
1109         retS[conn[j]]=true;
1110   int sz=0;
1111   for(int i=0;i<maxElt;i++)
1112     if(retS[i])
1113       sz++;
1114   DataArrayInt *ret=DataArrayInt::New();
1115   ret->alloc(sz,1);
1116   int *retPtr=ret->getPointer();
1117   for(int i=0;i<maxElt;i++)
1118     if(retS[i])
1119       *retPtr++=i;
1120   return ret;
1121 }
1122
1123 /*!
1124  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1125  * \sa MEDCouplingUMesh::getNodeIdsInUse
1126  */
1127 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const throw(INTERP_KERNEL::Exception)
1128 {
1129   int nbOfNodes=(int)nodeIdsInUse.size();
1130   int nbOfCells=getNumberOfCells();
1131   const int *connIndex=_nodal_connec_index->getConstPointer();
1132   const int *conn=_nodal_connec->getConstPointer();
1133   for(int i=0;i<nbOfCells;i++)
1134     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1135       if(conn[j]>=0)
1136         {
1137           if(conn[j]<nbOfNodes)
1138             nodeIdsInUse[conn[j]]=true;
1139           else
1140             {
1141               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1142               throw INTERP_KERNEL::Exception(oss.str().c_str());
1143             }
1144         }
1145 }
1146
1147 /*!
1148  * Array returned is the correspondance in \b old \b to \b new format (that's why 'nbrOfNodesInUse' is returned too).
1149  * The returned array is newly created and should be dealt by the caller.
1150  * To retrieve the new to old format the user can use DataArrayInt::invertArrayO2N2N2O method.
1151  * The size of returned array is the number of nodes of 'this'.
1152  * -1 values in returned array means that the corresponding node never appear in any nodal connectivity of cells constituting 'this'.
1153  * @param [out] nbrOfNodesInUse out parameter that specifies how many of nodes in 'this' is really used in nodal connectivity.
1154  * @return a newly allocated DataArrayInt that tells for each nodeid in \b this if it is unused (-1) or used (the corresponding new id)
1155  * \throw if a cell contains in its nodal connectivity a node id >= nb of nodes an exception will be thrown.
1156  * \sa MEDCouplingUMesh::computeNodeIdsAlg
1157  */
1158 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const throw(INTERP_KERNEL::Exception)
1159 {
1160   nbrOfNodesInUse=-1;
1161   int nbOfNodes=getNumberOfNodes();
1162   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
1163   ret->alloc(nbOfNodes,1);
1164   int *traducer=ret->getPointer();
1165   std::fill(traducer,traducer+nbOfNodes,-1);
1166   int nbOfCells=getNumberOfCells();
1167   const int *connIndex=_nodal_connec_index->getConstPointer();
1168   const int *conn=_nodal_connec->getConstPointer();
1169   for(int i=0;i<nbOfCells;i++)
1170     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1171       if(conn[j]>=0)
1172         {
1173           if(conn[j]<nbOfNodes)
1174             traducer[conn[j]]=1;
1175           else
1176             {
1177               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1178               throw INTERP_KERNEL::Exception(oss.str().c_str());
1179             }
1180         }
1181   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1182   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1183   return ret.retn();
1184 }
1185
1186 /*!
1187  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1188  * For each cell in \b this the number of nodes constituting cell is computed.
1189  * Excepted for poyhedrons, the result can be deduced by performing a deltaShiftIndex on the nodal connectivity index in \b this minus 1.
1190  * For polyhedrons, the face separation (-1) are excluded from the couting.
1191  * 
1192  * \return a newly allocated array
1193  */
1194 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const throw(INTERP_KERNEL::Exception)
1195 {
1196   checkConnectivityFullyDefined();
1197   int nbOfCells=getNumberOfCells();
1198   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
1199   ret->alloc(nbOfCells,1);
1200   int *retPtr=ret->getPointer();
1201   const int *conn=getNodalConnectivity()->getConstPointer();
1202   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1203   for(int i=0;i<nbOfCells;i++,retPtr++)
1204     {
1205       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1206         *retPtr=connI[i+1]-connI[i]-1;
1207       else
1208         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1209     }
1210   return ret.retn();
1211 }
1212
1213 /*!
1214  * Array returned is the correspondance in \b old \b to \b new format. The returned array is newly created and should be dealt by the caller.
1215  * The maximum value stored in returned array is the number of nodes of 'this' minus 1 after call of this method.
1216  * The size of returned array is the number of nodes of the old (previous to the call of this method) number of nodes.
1217  * -1 values in returned array means that the corresponding old node is no more used.
1218  */
1219 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer() throw(INTERP_KERNEL::Exception)
1220 {
1221   int newNbOfNodes=-1;
1222   DataArrayInt *traducer=getNodeIdsInUse(newNbOfNodes);
1223   renumberNodes(traducer->getConstPointer(),newNbOfNodes);
1224   return traducer;
1225 }
1226
1227 /*!
1228  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1229  * The semantic of 'compType' is specified in MEDCouplingUMesh::zipConnectivityTraducer method.
1230  */
1231 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1232 {
1233   switch(compType)
1234     {
1235     case 0:
1236       return AreCellsEqual0(conn,connI,cell1,cell2);
1237     case 1:
1238       return AreCellsEqual1(conn,connI,cell1,cell2);
1239     case 2:
1240       return AreCellsEqual2(conn,connI,cell1,cell2);
1241     case 3:
1242       return AreCellsEqual3(conn,connI,cell1,cell2);
1243     case 7:
1244       return AreCellsEqual7(conn,connI,cell1,cell2);
1245     }
1246   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2 or 3.");
1247 }
1248
1249 /*!
1250  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 0.
1251  */
1252 int MEDCouplingUMesh::AreCellsEqual0(const int *conn, const int *connI, int cell1, int cell2)
1253 {
1254   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1255     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1256   return 0;
1257 }
1258
1259 /*!
1260  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 1.
1261  */
1262 int MEDCouplingUMesh::AreCellsEqual1(const int *conn, const int *connI, int cell1, int cell2)
1263 {
1264   int sz=connI[cell1+1]-connI[cell1];
1265   if(sz==connI[cell2+1]-connI[cell2])
1266     {
1267       if(conn[connI[cell1]]==conn[connI[cell2]])
1268         {
1269           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1270           unsigned dim=cm.getDimension();
1271           if(dim!=3)
1272             {
1273               if(dim!=1)
1274                 {
1275                   int sz1=2*(sz-1);
1276                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1277                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1278                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1279                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1280                   return work!=tmp+sz1?1:0;
1281                 }
1282               else
1283                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1284             }
1285           else
1286             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqual1 : not implemented yet for meshdim == 3 !");
1287         }
1288     }
1289   return 0;
1290 }
1291
1292 /*!
1293  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 2.
1294  */
1295 int MEDCouplingUMesh::AreCellsEqual2(const int *conn, const int *connI, int cell1, int cell2)
1296 {
1297   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1298     {
1299       if(conn[connI[cell1]]==conn[connI[cell2]])
1300         {
1301           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1302           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1303           return s1==s2?1:0;
1304         }
1305     }
1306   return 0;
1307 }
1308
1309 /*!
1310  * This method is less restrictive than AreCellsEqual2. Here the geometric type is absolutely not taken into account !
1311  */
1312 int MEDCouplingUMesh::AreCellsEqual3(const int *conn, const int *connI, int cell1, int cell2)
1313 {
1314   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1315     {
1316       std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1317       std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1318       return s1==s2?1:0;
1319     }
1320   return 0;
1321 }
1322
1323 /*!
1324  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 7.
1325  */
1326 int MEDCouplingUMesh::AreCellsEqual7(const int *conn, const int *connI, int cell1, int cell2)
1327 {
1328   int sz=connI[cell1+1]-connI[cell1];
1329   if(sz==connI[cell2+1]-connI[cell2])
1330     {
1331       if(conn[connI[cell1]]==conn[connI[cell2]])
1332         {
1333           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1334           unsigned dim=cm.getDimension();
1335           if(dim!=3)
1336             {
1337               if(dim!=1)
1338                 {
1339                   int sz1=2*(sz-1);
1340                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1341                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1342                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1343                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1344                   if(work!=tmp+sz1)
1345                     return 1;
1346                   else
1347                     {
1348                       std::reverse_iterator<int *> it1((int *)tmp+sz1);
1349                       std::reverse_iterator<int *> it2((int *)tmp);
1350                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1351                         return 2;
1352                       else
1353                         return 0;
1354                     }
1355                   
1356                   return work!=tmp+sz1?1:0;
1357                 }
1358               else
1359                 {//case of SEG2 and SEG3
1360                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1361                     return 1;
1362                   if(!cm.isQuadratic())
1363                     {
1364                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1365                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1366                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1367                         return 2;
1368                       return 0;
1369                     }
1370                   else
1371                     {
1372                       if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1373                         return 2;
1374                       return 0;
1375                     }
1376                 }
1377             }
1378           else
1379             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqual7 : not implemented yet for meshdim == 3 !");
1380         }
1381     }
1382   return 0;
1383 }
1384
1385
1386 /*!
1387  * This method compares 2 cells coming from two unstructured meshes : 'this' and 'other'.
1388  * This method compares 2 cells having the same id 'cellId' in 'this' and 'other'.
1389  */
1390 bool MEDCouplingUMesh::areCellsFrom2MeshEqual(const MEDCouplingUMesh *other, int cellId, double prec) const
1391 {
1392   if(getTypeOfCell(cellId)!=other->getTypeOfCell(cellId))
1393     return false;
1394   std::vector<int> c1,c2;
1395   getNodeIdsOfCell(cellId,c1);
1396   other->getNodeIdsOfCell(cellId,c2);
1397   std::size_t sz=c1.size();
1398   if(sz!=c2.size())
1399     return false;
1400   for(std::size_t i=0;i<sz;i++)
1401     {
1402       std::vector<double> n1,n2;
1403       getCoordinatesOfNode(c1[0],n1);
1404       other->getCoordinatesOfNode(c2[0],n2);
1405       std::transform(n1.begin(),n1.end(),n2.begin(),n1.begin(),std::minus<double>());
1406       std::transform(n1.begin(),n1.end(),n1.begin(),std::ptr_fun<double,double>(fabs));
1407       if(*std::max_element(n1.begin(),n1.end())>prec)
1408         return false;
1409     }
1410   return true;
1411 }
1412
1413 /*!
1414  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1415  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1416  * and result remains unchanged.
1417  * The semantic of 'compType' is specified in MEDCouplingUMesh::zipConnectivityTraducer method.
1418  * If in 'candidates' pool -1 value is considered as an empty value.
1419  * WARNING this method returns only ONE set of result !
1420  */
1421 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1422 {
1423   if(candidates.size()<1)
1424     return false;
1425   bool ret=false;
1426   std::vector<int>::const_iterator iter=candidates.begin();
1427   int start=(*iter++);
1428   for(;iter!=candidates.end();iter++)
1429     {
1430       int status=AreCellsEqual(conn,connI,start,*iter,compType);
1431       if(status!=0)
1432         {
1433           if(!ret)
1434             {
1435               result->pushBackSilent(start);
1436               ret=true;
1437             }
1438           if(status==1)
1439             result->pushBackSilent(*iter);
1440           else
1441             result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1442         }
1443     }
1444   return ret;
1445 }
1446
1447 /*!
1448  * This method find cells that are cells equal (regarding \a compType) in \a this. The comparison is specified by \a compType.
1449  * This method keeps the coordiantes of \a this. This method is time consuming and is called 
1450  *
1451  * \param [in] compType input specifying the technique used to compare cells each other.
1452  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1453  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1454  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1455  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1456  * can be used for users not sensitive to orientation of cell
1457  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1458  * \param [out] commonCells
1459  * \param [out] commonCellsI
1460  * \return the correspondance array old to new in a newly allocated array.
1461  * 
1462  */
1463 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const throw(INTERP_KERNEL::Exception)
1464 {
1465   checkConnectivityFullyDefined();
1466   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1467   getReverseNodalConnectivity(revNodal,revNodalI);
1468   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1469 }
1470
1471 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1472                                           DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) throw(INTERP_KERNEL::Exception)
1473 {
1474   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1475   int nbOfCells=nodalI->getNumberOfTuples()-1;
1476   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1477   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1478   const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1479   std::vector<bool> isFetched(nbOfCells,false);
1480   if(startCellId==0)
1481     {
1482       for(int i=0;i<nbOfCells;i++)
1483         {
1484           if(!isFetched[i])
1485             {
1486               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1487               std::vector<int> v,v2;
1488               if(connOfNode!=connPtr+connIPtr[i+1])
1489                 {
1490                   const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1491                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1492                   connOfNode++;
1493                 }
1494               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1495                 if(*connOfNode>=0)
1496                   {
1497                     v=v2;
1498                     const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1499                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1500                     v2.resize(std::distance(v2.begin(),it));
1501                   }
1502               if(v2.size()>1)
1503                 {
1504                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1505                     {
1506                       int pos=commonCellsI->back();
1507                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1508                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1509                         isFetched[*it]=true;
1510                     }
1511                 }
1512             }
1513         }
1514     }
1515   else
1516     {
1517       for(int i=startCellId;i<nbOfCells;i++)
1518         {
1519           if(!isFetched[i])
1520             {
1521               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1522               std::vector<int> v,v2;
1523               if(connOfNode!=connPtr+connIPtr[i+1])
1524                 {
1525                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1526                   connOfNode++;
1527                 }
1528               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1529                 if(*connOfNode>=0)
1530                   {
1531                     v=v2;
1532                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1533                     v2.resize(std::distance(v2.begin(),it));
1534                   }
1535               if(v2.size()>1)
1536                 {
1537                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1538                     {
1539                       int pos=commonCellsI->back();
1540                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1541                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1542                         isFetched[*it]=true;
1543                     }
1544                 }
1545             }
1546         }
1547     }
1548   commonCellsArr=commonCells.retn();
1549   commonCellsIArr=commonCellsI.retn();
1550 }
1551
1552 /*!
1553  * This method could potentially modify \a this. This method merges cells if there are cells equal in \a this. The comparison is specified by \a compType.
1554  * This method keeps the coordiantes of \a this.
1555  *
1556  * \param [in] compType input specifying the technique used to compare cells each other.
1557  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1558  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1559  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1560  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1561  * can be used for users not sensitive to orientation of cell
1562  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned
1563  * \return the correspondance array old to new in a newly allocated array.
1564  * 
1565  * \warning This method modifies can modify significantly the geometric type order in \a this.
1566  * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1567  */
1568 DataArrayInt *MEDCouplingUMesh::zipConnectivityTraducer(int compType, int startCellId) throw(INTERP_KERNEL::Exception)
1569 {
1570   DataArrayInt *commonCells=0,*commonCellsI=0;
1571   findCommonCells(compType,startCellId,commonCells,commonCellsI);
1572   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1573   int newNbOfCells=-1;
1574   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(getNumberOfCells(),commonCells->begin(),commonCellsI->begin(),
1575                                                                                                           commonCellsI->end(),newNbOfCells);
1576   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret2=ret->invertArrayO2N2N2O(newNbOfCells);
1577   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> self=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret2->begin(),ret2->end(),true));
1578   setConnectivity(self->getNodalConnectivity(),self->getNodalConnectivityIndex(),true);
1579   return ret.retn();
1580 }
1581
1582 /*!
1583  * This method makes the assumption that 'this' and 'other' share the same coords. If not an exception will be thrown !
1584  * This method tries to determine if 'other' is fully included in 'this'. To compute that, this method works with connectivity as MEDCouplingUMesh::zipConnectivityTraducer method does. 
1585  * This method is close to MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith or MEDCouplingMesh::checkGeoEquivalWith with policy 20,21,or 22.
1586  * The main difference is that this method is not expected to throw exception.
1587  * This method has two outputs :
1588  *
1589  * @param compType is the comparison type. The possible values of this parameter are described in ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer method
1590  * @param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1591  * @return If 'other' is fully included in 'this 'true is returned. If not false is returned.
1592  */
1593 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const throw(INTERP_KERNEL::Exception)
1594 {
1595   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1596   int nbOfCells=getNumberOfCells();
1597   static const int possibleCompType[]={0,1,2};
1598   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1599     {
1600       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1601       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1602       oss << " !";
1603       throw INTERP_KERNEL::Exception(oss.str().c_str());
1604     }
1605   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1606   arr=o2n->substr(nbOfCells);
1607   arr->setName(other->getName());
1608   int tmp;
1609   if(other->getNumberOfCells()==0)
1610     return true;
1611   return arr->getMaxValue(tmp)<nbOfCells;
1612 }
1613
1614 /*!
1615  * This method makes the assumption that 'this' and 'other' share the same coords. If not an exception will be thrown !
1616  * This method tries to determine if \b other is fully included in \b this.
1617  * The main difference is that this method is not expected to throw exception.
1618  * This method has two outputs :
1619  *
1620  * @param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1621  * @return If 'other' is fully included in 'this 'true is returned. If not false is returned.
1622  */
1623 bool MEDCouplingUMesh::areCellsIncludedIn2(const MEDCouplingUMesh *other, DataArrayInt *& arr) const throw(INTERP_KERNEL::Exception)
1624 {
1625   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1626   DataArrayInt *commonCells=0,*commonCellsI=0;
1627   int thisNbCells=getNumberOfCells();
1628   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1629   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1630   const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1631   int otherNbCells=other->getNumberOfCells();
1632   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arr2=DataArrayInt::New();
1633   arr2->alloc(otherNbCells,1);
1634   arr2->fillWithZero();
1635   int *arr2Ptr=arr2->getPointer();
1636   int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1637   for(int i=0;i<nbOfCommon;i++)
1638     {
1639       int start=commonCellsPtr[commonCellsIPtr[i]];
1640       if(start<thisNbCells)
1641         {
1642           for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1643             {
1644               int sig=commonCellsPtr[j]>0?1:-1;
1645               int val=std::abs(commonCellsPtr[j])-1;
1646               if(val>=thisNbCells)
1647                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1648             }
1649         }
1650     }
1651   arr2->setName(other->getName());
1652   if(arr2->presenceOfValue(0))
1653     return false;
1654   arr=arr2.retn();
1655   return true;
1656 }
1657
1658 /*!
1659  * @param areNodesMerged if at least two nodes have been merged.
1660  * @return old to new node correspondance.
1661  */
1662 DataArrayInt *MEDCouplingUMesh::mergeNodes(double precision, bool& areNodesMerged, int& newNbOfNodes)
1663 {
1664   DataArrayInt *ret=buildPermArrayForMergeNode(precision,-1,areNodesMerged,newNbOfNodes);
1665   if(areNodesMerged)
1666     renumberNodes(ret->getConstPointer(),newNbOfNodes);
1667   return ret;
1668 }
1669
1670 /*!
1671  * Idem ParaMEDMEM::MEDCouplingUMesh::mergeNodes method except that the merged nodes are meld into the barycenter of them.
1672  */
1673 DataArrayInt *MEDCouplingUMesh::mergeNodes2(double precision, bool& areNodesMerged, int& newNbOfNodes)
1674 {
1675   DataArrayInt *ret=buildPermArrayForMergeNode(precision,-1,areNodesMerged,newNbOfNodes);
1676   if(areNodesMerged)
1677     renumberNodes2(ret->getConstPointer(),newNbOfNodes);
1678   return ret;
1679 }
1680
1681 /*!
1682  * This method tries to use 'other' coords and use it for 'this'. If no exception was thrown after the call of this method :
1683  * this->_coords==other->_coords. If an exception is thrown 'this' remains unchanged.
1684  * Contrary to MEDCouplingUMesh::tryToShareSameCoords method this method makes a deeper analyze of coordinates (and so more expensive) than simple equality.
1685  * Two nodes one in 'this' and other in 'other' are considered equal if the distance between the two is lower than epsilon.
1686  */
1687 void MEDCouplingUMesh::tryToShareSameCoordsPermute(const MEDCouplingPointSet& other, double epsilon) throw(INTERP_KERNEL::Exception)
1688 {
1689   const DataArrayDouble *coords=other.getCoords();
1690   if(!coords)
1691     throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute : No coords specified in other !");
1692   if(!_coords)
1693     throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute : No coords specified in this whereas there is any in other !");
1694   int otherNbOfNodes=other.getNumberOfNodes();
1695   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=MergeNodesArray(&other,this);
1696   _coords->incrRef();
1697   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> oldCoords=_coords;
1698   setCoords(newCoords);
1699   bool areNodesMerged;
1700   int newNbOfNodes;
1701   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=buildPermArrayForMergeNode(epsilon,otherNbOfNodes,areNodesMerged,newNbOfNodes);
1702   if(!areNodesMerged)
1703     {
1704       setCoords(oldCoords);
1705       throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute fails : no nodes are mergeable with specified given epsilon !");
1706     }
1707   int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+otherNbOfNodes);
1708   const int *pt=std::find_if(da->getConstPointer()+otherNbOfNodes,da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
1709   if(pt!=da->getConstPointer()+da->getNbOfElems())
1710     {
1711       setCoords(oldCoords);
1712       throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute fails : some nodes in this are not in other !");
1713     }
1714   setCoords(oldCoords);
1715   renumberNodesInConn(da->getConstPointer()+otherNbOfNodes);
1716   setCoords(coords);
1717 }
1718
1719 /*!
1720  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1721  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1722  * cellIds is not given explicitely but by a range python like.
1723  * 
1724  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see ParaMEDMEM::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1725  * \return a newly allocated
1726  * 
1727  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1728  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1729  */
1730 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf2(int start, int end, int step, bool keepCoords) const throw(INTERP_KERNEL::Exception)
1731 {
1732   if(getMeshDimension()!=-1)
1733     {
1734       MEDCouplingUMesh *ret=buildPartOfMySelfKeepCoords2(start,end,step);
1735       if(!keepCoords)
1736         ret->zipCoords();
1737       return ret;
1738     }
1739   else
1740     {
1741       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelf2 for -1 dimension mesh ");
1742       if(newNbOfCells!=1)
1743         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1744       if(start!=0)
1745         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1746       incrRef();
1747       return const_cast<MEDCouplingUMesh *>(this);
1748     }
1749 }
1750
1751 /*!
1752  * build a sub part of \b this. This sub part is defined by the cell ids contained in the array in [begin,end).
1753  * @param begin begin of array containing the cell ids to keep.
1754  * @param end end of array of cell ids to keep. \b WARNING end param is \b not included ! Idem STL standard definitions.
1755  * @param keepCoords that specifies if you want or not to keep coords as this or zip it (see ParaMEDMEM::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1756  * 
1757  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1758  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1759  */
1760 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1761 {
1762   if(getMeshDimension()!=-1)
1763     {
1764       MEDCouplingUMesh *ret=buildPartOfMySelfKeepCoords(begin,end);
1765       if(!keepCoords)
1766         ret->zipCoords();
1767       return ret;
1768     }
1769   else
1770     {
1771       if(end-begin!=1)
1772         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1773       if(begin[0]!=0)
1774         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1775       incrRef();
1776       return const_cast<MEDCouplingUMesh *>(this);
1777     }
1778 }
1779
1780 /*!
1781  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1782  *
1783  * This method allows to partially modify some cells in \b this (whose list is specified by [\b cellIdsBg, \b cellIdsEnd) ) with cells coming in \b otherOnSameCoordsThanThis.
1784  * Size of [\b cellIdsBg, \b cellIdsEnd) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1785  * The number of cells of \b this will remain the same with this method.
1786  *
1787  * \param [in] begin begin of cell ids (included) of cells in this to assign
1788  * \param [in] end end of cell ids (excluded) of cells in this to assign
1789  * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd).
1790  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1791  */
1792 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis) throw(INTERP_KERNEL::Exception)
1793 {
1794   checkConnectivityFullyDefined();
1795   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1796   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1797     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1798   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1799     {
1800       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1801       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1802       throw INTERP_KERNEL::Exception(oss.str().c_str());
1803     }
1804   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
1805   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1806     {
1807       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1808       throw INTERP_KERNEL::Exception(oss.str().c_str());
1809     }
1810   int nbOfCells=getNumberOfCells();
1811   bool easyAssign=true;
1812   const int *connI=_nodal_connec_index->getConstPointer();
1813   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1814   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
1815     {
1816       if(*it>=0 && *it<nbOfCells)
1817         {
1818           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
1819         }
1820       else
1821         {
1822           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
1823           throw INTERP_KERNEL::Exception(oss.str().c_str());
1824         }
1825     }
1826   if(easyAssign)
1827     {
1828       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1829       computeTypes();
1830     }
1831   else
1832     {
1833       DataArrayInt *arrOut=0,*arrIOut=0;
1834       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1835                                                arrOut,arrIOut);
1836       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1837       setConnectivity(arrOut,arrIOut,true);
1838     }
1839 }
1840
1841 void MEDCouplingUMesh::setPartOfMySelf2(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis) throw(INTERP_KERNEL::Exception)
1842 {
1843   checkConnectivityFullyDefined();
1844   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1845   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1846     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf2 : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1847   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1848     {
1849       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1850       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1851       throw INTERP_KERNEL::Exception(oss.str().c_str());
1852     }
1853   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelf2 : ");
1854   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1855     {
1856       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1857       throw INTERP_KERNEL::Exception(oss.str().c_str());
1858     }
1859   int nbOfCells=getNumberOfCells();
1860   bool easyAssign=true;
1861   const int *connI=_nodal_connec_index->getConstPointer();
1862   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1863   int it=start;
1864   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
1865     {
1866       if(it>=0 && it<nbOfCells)
1867         {
1868           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
1869         }
1870       else
1871         {
1872           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
1873           throw INTERP_KERNEL::Exception(oss.str().c_str());
1874         }
1875     }
1876   if(easyAssign)
1877     {
1878       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1879       computeTypes();
1880     }
1881   else
1882     {
1883       DataArrayInt *arrOut=0,*arrIOut=0;
1884       MEDCouplingUMesh::SetPartOfIndexedArrays2(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1885                                                 arrOut,arrIOut);
1886       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1887       setConnectivity(arrOut,arrIOut,true);
1888     }
1889 }                      
1890
1891 DataArrayInt *MEDCouplingUMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const
1892 {
1893   DataArrayInt *cellIdsKept=0;
1894   fillCellIdsToKeepFromNodeIds(partBg,partEnd,true,cellIdsKept);
1895   cellIdsKept->setName(getName());
1896   return cellIdsKept;
1897 }
1898
1899 /*!
1900  * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
1901  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
1902  * Parameter 'fullyIn' specifies if a cell that has part of its nodes in ids array is kept or not.
1903  * If 'fullyIn' is true only cells whose ids are \b fully contained in ['begin','end') tab will be kept.
1904  *
1905  * \param [in] begin input start of array of node ids.
1906  * \param [in] end input end of array of node ids.
1907  * \param [in] fullyIn input that specifies if all node ids must be in ['begin','end') array to consider cell to be in.
1908  * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
1909  */
1910 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
1911 {
1912   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
1913   checkConnectivityFullyDefined();
1914   int tmp=-1;
1915   int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
1916   std::vector<bool> fastFinder(sz,false);
1917   for(const int *work=begin;work!=end;work++)
1918     if(*work>=0 && *work<sz)
1919       fastFinder[*work]=true;
1920   int nbOfCells=getNumberOfCells();
1921   const int *conn=getNodalConnectivity()->getConstPointer();
1922   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
1923   for(int i=0;i<nbOfCells;i++)
1924     {
1925       int ref=0,nbOfHit=0;
1926       for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
1927         if(*work2>=0)
1928           {
1929             ref++;
1930             if(fastFinder[*work2])
1931               nbOfHit++;
1932           }
1933       if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
1934         cellIdsKept->pushBackSilent(i);
1935     }
1936   cellIdsKeptArr=cellIdsKept.retn();
1937 }
1938
1939 /*!
1940  * This method is very close too MEDCouplingUMesh::buildPartOfMySelfNode. The difference is that it returns directly ids.
1941  */
1942 DataArrayInt *MEDCouplingUMesh::getCellIdsLyingOnNodes(const int *begin, const int *end, bool fullyIn) const
1943 {
1944   DataArrayInt *cellIdsKept=0;
1945   fillCellIdsToKeepFromNodeIds(begin,end,fullyIn,cellIdsKept);
1946   cellIdsKept->setName(getName());
1947   return cellIdsKept;
1948 }
1949
1950 /*!
1951  * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
1952  * The return newly allocated mesh will share the same coordinates as 'this'.
1953  * Parameter 'fullyIn' specifies if a cell that has part of its nodes in ids array is kept or not.
1954  * If 'fullyIn' is true only cells whose ids are \b fully contained in ['begin','end') tab will be kept.
1955  */
1956 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
1957 {
1958   DataArrayInt *cellIdsKept=0;
1959   fillCellIdsToKeepFromNodeIds(begin,end,fullyIn,cellIdsKept);
1960   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIdsKept2(cellIdsKept);
1961   return buildPartOfMySelf(cellIdsKept->begin(),cellIdsKept->end(),true);
1962 }
1963
1964 /*!
1965  * Contrary to MEDCouplingUMesh::buildPartOfMySelfNode method this method builds a mesh with a meshDimension equal to
1966  * this->getMeshDimension()-1. The return newly allocated mesh will share the same coordinates as 'this'.
1967  * Parameter 'fullyIn' specifies if a face that has part of its nodes in ids array is kept or not.
1968  * If 'fullyIn' is true only faces whose ids are \b fully contained in ['begin','end') tab will be kept.
1969  */
1970 MEDCouplingPointSet *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
1971 {
1972   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
1973   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
1974   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1975   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
1976   return subMesh->buildPartOfMySelfNode(begin,end,fullyIn);
1977 }
1978
1979 /*!
1980  * This method returns a mesh with meshDim=this->getMeshDimension()-1.
1981  * This returned mesh contains cells that are linked with one and only one cell of this.
1982  * @param keepCoords specifies if ParaMEDMEM::MEDCouplingUMesh::zipCoords is called on returned mesh before being returned. If true zipCoords is \b NOT called, if false, zipCoords is called.
1983  * @return mesh with ref counter equal to 1.
1984  */
1985 MEDCouplingPointSet *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
1986 {
1987   DataArrayInt *desc=DataArrayInt::New();
1988   DataArrayInt *descIndx=DataArrayInt::New();
1989   DataArrayInt *revDesc=DataArrayInt::New();
1990   DataArrayInt *revDescIndx=DataArrayInt::New();
1991   //
1992   MEDCouplingUMesh *meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1993   revDesc->decrRef();
1994   desc->decrRef();
1995   descIndx->decrRef();
1996   int nbOfCells=meshDM1->getNumberOfCells();
1997   const int *revDescIndxC=revDescIndx->getConstPointer();
1998   std::vector<int> boundaryCells;
1999   for(int i=0;i<nbOfCells;i++)
2000     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2001       boundaryCells.push_back(i);
2002   revDescIndx->decrRef();
2003   MEDCouplingPointSet *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2004   meshDM1->decrRef();
2005   return ret;
2006 }
2007
2008 /*!
2009  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2010  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2011  * This method makes the assumption that 'this' is fully defined (coords,connectivity). If not an exception will be thrown. 
2012  */
2013 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const throw(INTERP_KERNEL::Exception)
2014 {
2015   checkFullyDefined();
2016   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
2017   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
2018   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
2019   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
2020   //
2021   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2022   desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2023   //
2024   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2025   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faceIds=tmp->getIdsEqual(1); tmp=(DataArrayInt*)0;
2026   const int *revDescPtr=revDesc->getConstPointer();
2027   const int *revDescIndxPtr=revDescIndx->getConstPointer();
2028   int nbOfCells=getNumberOfCells();
2029   std::vector<bool> ret1(nbOfCells,false);
2030   int sz=0;
2031   for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2032     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2033       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2034   //
2035   DataArrayInt *ret2=DataArrayInt::New();
2036   ret2->alloc(sz,1);
2037   int *ret2Ptr=ret2->getPointer();
2038   sz=0;
2039   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2040     if(*it)
2041       *ret2Ptr++=sz;
2042   ret2->setName("BoundaryCells");
2043   return ret2;
2044 }
2045
2046 /*!
2047  * This method find in \b this cells ids that lie on mesh \b otherDimM1OnSameCoords.
2048  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2049  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2050  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2051  *
2052  * s0 is the cells ids set in \b this lying on at least one node in fetched nodes in \b otherDimM1OnSameCoords.
2053  * This method method returns cells ids set s = s1 + s2 where :
2054  * 
2055  *  - s1 are cells ids in \b this whose dim-1 constituent equals a cell in \b otherDimM1OnSameCoords.
2056  *  - s2 are cells ids in \b s0 - \b s1 whose at least two neighbors are in s1.
2057  *
2058  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2059  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2060  *
2061  * \param [out] cellIdsRk0 a newly allocated array containing cells ids in \b this containg s0 in above algorithm.
2062  * \param [out] cellIdsRk1 a newly allocated array containing cells ids of s1+s2 \b into \b cellIdsRk0 subset. To get absolute ids of s1+s2 simply invoke
2063  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2064  */
2065 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const throw(INTERP_KERNEL::Exception)
2066 {
2067   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2068     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2069   checkConnectivityFullyDefined();
2070   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2071   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2072     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2073   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2074   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2075   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2076   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2077   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2078   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2079   DataArrayInt *idsOtherInConsti=0;
2080   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2081   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2082   if(!b)
2083     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2084   std::set<int> s1;
2085   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2086     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2087   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2088   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1Comparr_renum1=s1arr_renum1->buildComplement(s0arr->getNumberOfTuples());
2089   DataArrayInt *neighThisPart=0,*neighIThisPart=0;
2090   ComputeNeighborsOfCellsAdv(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart,neighThisPart,neighIThisPart);
2091   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighThisPartAuto(neighThisPart),neighIThisPartAuto(neighIThisPart);
2092   ExtractFromIndexedArrays(s1Comparr_renum1->begin(),s1Comparr_renum1->end(),neighThisPart,neighIThisPart,neighThisPart,neighIThisPart);// reuse of neighThisPart and neighIThisPart
2093   neighThisPartAuto=neighThisPart; neighIThisPartAuto=neighIThisPart;
2094   RemoveIdsFromIndexedArrays(s1Comparr_renum1->begin(),s1Comparr_renum1->end(),neighThisPart,neighIThisPart);
2095   neighThisPartAuto=0;
2096   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2_tmp=neighIThisPart->deltaShiftIndex();
2097   const int li[2]={0,1};
2098   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2_renum2=s2_tmp->getIdsNotEqualList(li,li+2);
2099   s2_renum2->transformWithIndArr(s1Comparr_renum1->begin(),s1Comparr_renum1->end());//s2_renum2==s2_renum1
2100   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s_renum1=DataArrayInt::Aggregate(s2_renum2,s1arr_renum1,0);
2101   s_renum1->sort();
2102   //
2103   cellIdsRk0=s0arr.retn();
2104   cellIdsRk1=s_renum1.retn();
2105 }
2106
2107 /*!
2108  * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2109  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2110  * 
2111  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2112  */
2113 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const throw(INTERP_KERNEL::Exception)
2114 {
2115   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
2116   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
2117   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
2118   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
2119   //
2120   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2121   revDesc=0; desc=0; descIndx=0;
2122   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2123   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> part=revDescIndx2->getIdsEqual(1);
2124   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2125 }
2126
2127 /*!
2128  * This methods returns set of nodes in a newly allocated array that the caller has to deal with.
2129  * The returned nodes ids are those lying on the boundary of \b this.
2130  */
2131 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2132 {
2133   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> skin=computeSkin();
2134   return skin->computeFetchedNodeIds();
2135 }
2136
2137 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const throw(INTERP_KERNEL::Exception)
2138 {
2139   incrRef();
2140   return const_cast<MEDCouplingUMesh *>(this);
2141 }
2142
2143 /*
2144  * This method renumber 'this' using 'newNodeNumbers' array of size this->getNumberOfNodes.
2145  * newNbOfNodes specifies the *std::max_element(newNodeNumbers,newNodeNumbers+this->getNumberOfNodes())
2146  * This value is asked because often known by the caller of this method.
2147  * This method, contrary to MEDCouplingMesh::renumberCells does NOT conserve the number of nodes before and after.
2148  *
2149  * @param newNodeNumbers array specifying the new numbering in old2New convention.
2150  * @param newNbOfNodes the new number of nodes.
2151  */
2152 void MEDCouplingUMesh::renumberNodes(const int *newNodeNumbers, int newNbOfNodes)
2153 {
2154   MEDCouplingPointSet::renumberNodes(newNodeNumbers,newNbOfNodes);
2155   renumberNodesInConn(newNodeNumbers);
2156 }
2157
2158 /*
2159  * This method renumber 'this' using 'newNodeNumbers' array of size this->getNumberOfNodes.
2160  * newNbOfNodes specifies the *std::max_element(newNodeNumbers,newNodeNumbers+this->getNumberOfNodes())
2161  * This value is asked because often known by the caller of this method.
2162  * This method, contrary to MEDCouplingMesh::renumberCells does NOT conserve the number of nodes before and after.
2163  * The difference with ParaMEDMEM::MEDCouplingUMesh::renumberNodes method is in the fact that the barycenter of merged nodes is computed here.
2164  *
2165  * @param newNodeNumbers array specifying the new numbering.
2166  * @param newNbOfNodes the new number of nodes.
2167  *
2168  */
2169 void MEDCouplingUMesh::renumberNodes2(const int *newNodeNumbers, int newNbOfNodes)
2170 {
2171   MEDCouplingPointSet::renumberNodes2(newNodeNumbers,newNbOfNodes);
2172   renumberNodesInConn(newNodeNumbers);
2173 }
2174
2175 /*!
2176  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2177  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2178  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2179  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considerd as needed to be duplicated.
2180  * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2181  *
2182  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2183  *             parameter is altered during the call.
2184  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2185  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2186  * \param [out] cellIdsNotModified cell ids int \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2187  *
2188  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2189  */
2190 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2191                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const throw(INTERP_KERNEL::Exception)
2192 {
2193   checkFullyDefined();
2194   otherDimM1OnSameCoords.checkFullyDefined();
2195   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2196     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2197   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2198     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2199   DataArrayInt *cellIdsRk0=0,*cellIdsRk1=0;
2200   findCellIdsLyingOn(otherDimM1OnSameCoords,cellIdsRk0,cellIdsRk1);
2201   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIdsRk0Auto(cellIdsRk0),cellIdsRk1Auto(cellIdsRk1);
2202   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s0=cellIdsRk1->buildComplement(cellIdsRk0->getNumberOfTuples());
2203   s0->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2204   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0->begin(),s0->end(),true));
2205   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1=m0Part->computeFetchedNodeIds();
2206   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2=otherDimM1OnSameCoords.computeFetchedNodeIds();
2207   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s3=s2->buildSubstraction(s1);
2208   cellIdsRk1->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2209   //
2210   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellIdsRk1->begin(),cellIdsRk1->end(),true));
2211   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2212   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2213   DataArrayInt *idsTmp=0;
2214   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2215   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids(idsTmp);
2216   if(!b)
2217     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the given mdim-1 mesh in other is not a constituent of this !");
2218   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2219   DataArrayInt *tmp0=0,*tmp1=0;
2220   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2221   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neigh00(tmp0);
2222   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighI00(tmp1);
2223   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn0_torenum=MEDCouplingUMesh::ComputeSpreadZoneGradually(neigh00,neighI00);
2224   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2225   cellsToModifyConn0_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2226   cellsToModifyConn1_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2227   //
2228   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2229   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2230   nodeIdsToDuplicate=s3.retn();
2231 }
2232
2233 /*!
2234  * This method operates a modification of the connectivity and coords in \b this.
2235  * Every time that a node id in [\b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd) will append in nodal connectivity of \b this 
2236  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2237  * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2238  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2239  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2240  * 
2241  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2242  * 
2243  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2244  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2245  */
2246 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd) throw(INTERP_KERNEL::Exception)
2247 {
2248   int nbOfNodes=getNumberOfNodes();
2249   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2250   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2251 }
2252
2253 /*!
2254  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2255  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2256  * This method is an generalization of \ref ParaMEDMEM::MEDCouplingUMesh::shiftNodeNumbersInConn "shiftNodeNumbersInConn method".
2257  * @param [in] newNodeNumbers in old2New convention
2258  */
2259 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2260 {
2261   checkConnectivityFullyDefined();
2262   int *conn=getNodalConnectivity()->getPointer();
2263   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2264   int nbOfCells=getNumberOfCells();
2265   for(int i=0;i<nbOfCells;i++)
2266     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2267       {
2268         int& node=conn[iconn];
2269         if(node>=0)//avoid polyhedron separator
2270           {
2271             node=newNodeNumbersO2N[node];
2272           }
2273       }
2274   _nodal_connec->declareAsNew();
2275   updateTime();
2276 }
2277
2278 /*!
2279  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2280  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2281  * This method is an specialization of \ref ParaMEDMEM::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2282  * 
2283  * @param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2284  */
2285 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta) throw(INTERP_KERNEL::Exception)
2286 {
2287   checkConnectivityFullyDefined();
2288   int *conn=getNodalConnectivity()->getPointer();
2289   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2290   int nbOfCells=getNumberOfCells();
2291   for(int i=0;i<nbOfCells;i++)
2292     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2293       {
2294         int& node=conn[iconn];
2295         if(node>=0)//avoid polyhedron separator
2296           {
2297             node+=delta;
2298           }
2299       }
2300   _nodal_connec->declareAsNew();
2301   updateTime();
2302 }
2303
2304 /*!
2305  * This method operates a modification of the connectivity in \b this.
2306  * Coordinates are \b NOT considered here and will remain unchanged by this method. this->_coords can ever been null for the needs of this method.
2307  * Every time that a node id in [\b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd) will append in nodal connectivity of \b this 
2308  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2309  * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2310  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2311  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2312  * 
2313  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2314  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2315  * 
2316  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2317  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2318  * \param [in] offset the offset applied to all node ids in connectivity that are in [nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd). 
2319  */
2320 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset) throw(INTERP_KERNEL::Exception)
2321 {
2322   checkConnectivityFullyDefined();
2323   std::map<int,int> m;
2324   int val=offset;
2325   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2326     m[*work]=val;
2327   int *conn=getNodalConnectivity()->getPointer();
2328   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2329   int nbOfCells=getNumberOfCells();
2330   for(int i=0;i<nbOfCells;i++)
2331     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2332       {
2333         int& node=conn[iconn];
2334         if(node>=0)//avoid polyhedron separator
2335           {
2336             std::map<int,int>::iterator it=m.find(node);
2337             if(it!=m.end())
2338               node=(*it).second;
2339           }
2340       }
2341   updateTime();
2342 }
2343
2344 /*!
2345  * This method renumbers cells of 'this' using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2346  *
2347  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2348  * After the call of this method the number of cells remains the same as before.
2349  *
2350  * If 'check' equals true the method will check that any elements in [old2NewBg;old2NewEnd) is unique ; if not
2351  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [old2NewBg;old2NewEnd) is not expected to
2352  * be strictly in [0;this->getNumberOfCells()).
2353  *
2354  * If 'check' equals false the method will not check the content of [old2NewBg;old2NewEnd).
2355  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [old2NewBg;old2NewEnd) should be unique and
2356  * should be contained in[0;this->getNumberOfCells()).
2357  * 
2358  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2359  */
2360 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check) throw(INTERP_KERNEL::Exception)
2361 {
2362   checkConnectivityFullyDefined();
2363   int nbCells=getNumberOfCells();
2364   const int *array=old2NewBg;
2365   if(check)
2366     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2367   //
2368   const int *conn=_nodal_connec->getConstPointer();
2369   const int *connI=_nodal_connec_index->getConstPointer();
2370   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
2371   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2372   newConn->copyStringInfoFrom(*_nodal_connec);
2373   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
2374   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2375   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2376   //
2377   int *newC=newConn->getPointer();
2378   int *newCI=newConnI->getPointer();
2379   int loc=0;
2380   newCI[0]=loc;
2381   for(int i=0;i<nbCells;i++)
2382     {
2383       std::size_t pos=std::distance(array,std::find(array,array+nbCells,i));
2384       int nbOfElts=connI[pos+1]-connI[pos];
2385       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2386       loc+=nbOfElts;
2387       newCI[i+1]=loc;
2388     }
2389   //
2390   setConnectivity(newConn,newConnI);
2391   if(check)
2392     delete [] const_cast<int *>(array);
2393 }
2394
2395 /*!
2396  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox'.
2397  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2398  * added in 'elems' parameter.
2399  */
2400 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2401 {
2402   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2403   if(getMeshDimension()==-1)
2404     {
2405       elems->pushBackSilent(0);
2406       return elems.retn();
2407     }
2408   int dim=getSpaceDimension();
2409   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2410   const int* conn      = getNodalConnectivity()->getConstPointer();
2411   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2412   const double* coords = getCoords()->getConstPointer();
2413   int nbOfCells=getNumberOfCells();
2414   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2415     {
2416       for (int i=0; i<dim; i++)
2417         {
2418           elem_bb[i*2]=std::numeric_limits<double>::max();
2419           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2420         }
2421
2422       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2423         {
2424           int node= conn[inode];
2425           if(node>=0)//avoid polyhedron separator
2426             {
2427               for (int idim=0; idim<dim; idim++)
2428                 {
2429                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2430                     {
2431                       elem_bb[idim*2] = coords[node*dim+idim] ;
2432                     }
2433                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2434                     {
2435                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2436                     }
2437                 }
2438             }
2439         }
2440       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2441         elems->pushBackSilent(ielem);
2442     }
2443   return elems.retn();
2444 }
2445
2446 /*!
2447  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2448  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2449  * added in 'elems' parameter.
2450  */
2451 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2452 {
2453   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2454   if(getMeshDimension()==-1)
2455     {
2456       elems->pushBackSilent(0);
2457       return elems.retn();
2458     }
2459   int dim=getSpaceDimension();
2460   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2461   const int* conn      = getNodalConnectivity()->getConstPointer();
2462   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2463   const double* coords = getCoords()->getConstPointer();
2464   int nbOfCells=getNumberOfCells();
2465   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2466     {
2467       for (int i=0; i<dim; i++)
2468         {
2469           elem_bb[i*2]=std::numeric_limits<double>::max();
2470           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2471         }
2472
2473       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2474         {
2475           int node= conn[inode];
2476           if(node>=0)//avoid polyhedron separator
2477             {
2478               for (int idim=0; idim<dim; idim++)
2479                 {
2480                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2481                     {
2482                       elem_bb[idim*2] = coords[node*dim+idim] ;
2483                     }
2484                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2485                     {
2486                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2487                     }
2488                 }
2489             }
2490         }
2491       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2492         elems->pushBackSilent(ielem);
2493     }
2494   return elems.retn();
2495 }
2496
2497 /*!
2498  * Returns the cell type of cell with id 'cellId'.
2499  */
2500 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2501 {
2502   const int *ptI=_nodal_connec_index->getConstPointer();
2503   const int *pt=_nodal_connec->getConstPointer();
2504   if(cellId>=0 && cellId<_nodal_connec_index->getNbOfElems()-1)
2505     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2506   else
2507     {
2508       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2509       throw INTERP_KERNEL::Exception(oss.str().c_str());
2510     }
2511 }
2512
2513 /*!
2514  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2515  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2516  * The coordinates array is not considered here.
2517  *
2518  * \param [in] type the geometric type
2519  * \return cell ids in this having geometric type \a type.
2520  */
2521 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception)
2522 {
2523   
2524   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
2525   ret->alloc(0,1);
2526   checkConnectivityFullyDefined();
2527   int nbCells=getNumberOfCells();
2528   int mdim=getMeshDimension();
2529   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2530   if(mdim!=(int)cm.getDimension())
2531     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2532   const int *ptI=_nodal_connec_index->getConstPointer();
2533   const int *pt=_nodal_connec->getConstPointer();
2534   for(int i=0;i<nbCells;i++)
2535     {
2536       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2537         ret->pushBackSilent(i);
2538     }
2539   return ret.retn();
2540 }
2541
2542 /*!
2543  * Returns nb of cells having the geometric type 'type'.
2544  */
2545 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2546 {
2547   const int *ptI=_nodal_connec_index->getConstPointer();
2548   const int *pt=_nodal_connec->getConstPointer();
2549   int nbOfCells=getNumberOfCells();
2550   int ret=0;
2551   for(int i=0;i<nbOfCells;i++)
2552     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2553       ret++;
2554   return ret;
2555 }
2556
2557 /*!
2558  * Appends the nodal connectivity in 'conn' of cell with id 'cellId'.
2559  * All elements added in conn can be used by MEDCouplingUMesh::getCoordinatesOfNode method.
2560  * That is to say -1 separator is omitted in returned conn.
2561  */
2562 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2563 {
2564   const int *ptI=_nodal_connec_index->getConstPointer();
2565   const int *pt=_nodal_connec->getConstPointer();
2566   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2567     if(*w>=0)
2568       conn.push_back(*w);
2569 }
2570
2571 std::string MEDCouplingUMesh::simpleRepr() const
2572 {
2573   static const char msg0[]="No coordinates specified !";
2574   std::ostringstream ret;
2575   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2576   ret << "Description of mesh : \"" << getDescription() << "\"\n";
2577   int tmpp1,tmpp2;
2578   double tt=getTime(tmpp1,tmpp2);
2579   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2580   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
2581   ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : ";
2582   if(_coords!=0)
2583     {
2584       const int spaceDim=getSpaceDimension();
2585       ret << spaceDim << "\nInfo attached on space dimension : ";
2586       for(int i=0;i<spaceDim;i++)
2587         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2588       ret << "\n";
2589     }
2590   else
2591     ret << msg0 << "\n";
2592   ret << "Number of nodes : ";
2593   if(_coords!=0)
2594     ret << getNumberOfNodes() << "\n";
2595   else
2596     ret << msg0 << "\n";
2597   ret << "Number of cells : ";
2598   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2599     ret << getNumberOfCells() << "\n";
2600   else
2601     ret << "No connectivity specified !" << "\n";
2602   ret << "Cell types present : ";
2603   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2604     {
2605       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2606       ret << cm.getRepr() << " ";
2607     }
2608   ret << "\n";
2609   return ret.str();
2610 }
2611
2612 std::string MEDCouplingUMesh::advancedRepr() const
2613 {
2614   std::ostringstream ret;
2615   ret << simpleRepr();
2616   ret << "\nCoordinates array : \n___________________\n\n";
2617   if(_coords)
2618     _coords->reprWithoutNameStream(ret);
2619   else
2620     ret << "No array set !\n";
2621   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2622   reprConnectivityOfThisLL(ret);
2623   return ret.str();
2624 }
2625
2626 /*!
2627  * This method returns a C++ code that is a dump of \a this.
2628  * This method will throw if this is not fully defined.
2629  */
2630 std::string MEDCouplingUMesh::cppRepr() const throw(INTERP_KERNEL::Exception)
2631 {
2632   static const char coordsName[]="coords";
2633   static const char connName[]="conn";
2634   static const char connIName[]="connI";
2635   checkFullyDefined();
2636   std::ostringstream ret; ret << "// coordinates" << std::endl;
2637   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2638   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2639   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2640   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2641   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2642   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2643   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2644   return ret.str();
2645 }
2646
2647 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2648 {
2649   std::ostringstream ret;
2650   reprConnectivityOfThisLL(ret);
2651   return ret.str();
2652 }
2653
2654 /*!
2655  * This method builds a newly allocated instance (with the same name than 'this') that the caller has the responsability to deal with.
2656  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2657  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2658  * some algos).
2659  * 
2660  * This method expects that 'this' has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2661  * This method analyzes the 3 arrays of 'this'. For each the following behaviour is done : if the array is null a newly one is created
2662  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2663  */
2664 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const throw(INTERP_KERNEL::Exception)
2665 {
2666   int mdim=getMeshDimension();
2667   if(mdim<0)
2668     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2669   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2670   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1,tmp2;
2671   bool needToCpyCT=true;
2672   if(!_nodal_connec)
2673     {
2674       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2675       needToCpyCT=false;
2676     }
2677   else
2678     {
2679       tmp1=_nodal_connec;
2680       tmp1->incrRef();
2681     }
2682   if(!_nodal_connec_index)
2683     {
2684       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2685       needToCpyCT=false;
2686     }
2687   else
2688     {
2689       tmp2=_nodal_connec_index;
2690       tmp2->incrRef();
2691     }
2692   ret->setConnectivity(tmp1,tmp2,false);
2693   if(needToCpyCT)
2694     ret->_types=_types;
2695   if(!_coords)
2696     {
2697       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2698       ret->setCoords(coords);
2699     }
2700   else
2701     ret->setCoords(_coords);
2702   return ret.retn();
2703 }
2704
2705 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
2706 {
2707   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2708     {
2709       int nbOfCells=getNumberOfCells();
2710       const int *c=_nodal_connec->getConstPointer();
2711       const int *ci=_nodal_connec_index->getConstPointer();
2712       for(int i=0;i<nbOfCells;i++)
2713         {
2714           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
2715           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
2716           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
2717           stream << "\n";
2718         }
2719     }
2720   else
2721     stream << "Connectivity not defined !\n";
2722 }
2723
2724 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2725 {
2726   const int *ptI=_nodal_connec_index->getConstPointer();
2727   const int *pt=_nodal_connec->getConstPointer();
2728   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2729     return ptI[cellId+1]-ptI[cellId]-1;
2730   else
2731     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
2732 }
2733
2734 /*!
2735  * This method is equivalent to MEDCouplingUMesh::getAllTypes excecpt that it returns only types of submesh which cell ids are in [begin,end).
2736  * This method avoids to compute explicitely submesh to get its types.
2737  */
2738 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const throw(INTERP_KERNEL::Exception)
2739 {
2740   checkFullyDefined();
2741   std::set<INTERP_KERNEL::NormalizedCellType> ret;
2742   const int *conn=_nodal_connec->getConstPointer();
2743   const int *connIndex=_nodal_connec_index->getConstPointer();
2744   for(const int *w=begin;w!=end;w++)
2745     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
2746   return ret;
2747 }
2748
2749 /*!
2750  * Method reserved for advanced users having prepared their connectivity before.
2751  * Arrays 'conn' and 'connIndex' will be aggregated without any copy and their counter will be incremented.
2752  */
2753 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
2754 {
2755   DataArrayInt::SetArrayIn(conn,_nodal_connec);
2756   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
2757   if(isComputingTypes)
2758     computeTypes();
2759   declareAsNew();
2760 }
2761
2762 /*!
2763  * Copy constructor. If 'deepCpy' is false 'this' is a shallow copy of other.
2764  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
2765  */
2766 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
2767                                                                                  _nodal_connec(0),_nodal_connec_index(0),
2768                                                                                 _types(other._types)
2769 {
2770   if(other._nodal_connec)
2771     _nodal_connec=other._nodal_connec->performCpy(deepCopy);
2772   if(other._nodal_connec_index)
2773     _nodal_connec_index=other._nodal_connec_index->performCpy(deepCopy);
2774 }
2775
2776 MEDCouplingUMesh::~MEDCouplingUMesh()
2777 {
2778   if(_nodal_connec)
2779     _nodal_connec->decrRef();
2780   if(_nodal_connec_index)
2781     _nodal_connec_index->decrRef();
2782 }
2783
2784 /*!
2785  * This method recomputes all cell types of 'this'.
2786  */
2787 void MEDCouplingUMesh::computeTypes()
2788 {
2789   if(_nodal_connec && _nodal_connec_index)
2790     {
2791       _types.clear();
2792       const int *conn=_nodal_connec->getConstPointer();
2793       const int *connIndex=_nodal_connec_index->getConstPointer();
2794       int nbOfElem=_nodal_connec_index->getNbOfElems()-1;
2795       for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
2796         _types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
2797     }
2798 }
2799
2800 /*!
2801  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
2802  */
2803 void MEDCouplingUMesh::checkFullyDefined() const throw(INTERP_KERNEL::Exception)
2804 {
2805   if(!_nodal_connec_index || !_nodal_connec || !_coords)
2806     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
2807 }
2808
2809 /*!
2810  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
2811  */
2812 void MEDCouplingUMesh::checkConnectivityFullyDefined() const throw(INTERP_KERNEL::Exception)
2813 {
2814   if(!_nodal_connec_index || !_nodal_connec)
2815     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
2816 }
2817
2818 int MEDCouplingUMesh::getNumberOfCells() const
2819
2820   if(_nodal_connec_index)
2821     return _nodal_connec_index->getNumberOfTuples()-1;
2822   else
2823     if(_mesh_dim==-1)
2824       return 1;
2825     else
2826       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
2827 }
2828
2829 int MEDCouplingUMesh::getMeshDimension() const
2830 {
2831   if(_mesh_dim<-1)
2832     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
2833   return _mesh_dim;
2834 }
2835
2836 /*!
2837  * This method is for test reason. Normally the integer returned is not useable by user.
2838  */
2839 int MEDCouplingUMesh::getMeshLength() const
2840 {
2841   return _nodal_connec->getNbOfElems();
2842 }
2843
2844 /*!
2845  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
2846  */
2847 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
2848 {
2849   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
2850   tinyInfo.push_back(getMeshDimension());
2851   tinyInfo.push_back(getNumberOfCells());
2852   if(_nodal_connec)
2853     tinyInfo.push_back(getMeshLength());
2854   else
2855     tinyInfo.push_back(-1);
2856 }
2857
2858 /*!
2859  * First step of unserialization process.
2860  */
2861 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
2862 {
2863   return tinyInfo[6]<=0;
2864 }
2865
2866 /*!
2867  * Second step of serialization process.
2868  * @param tinyInfo must be equal to the result given by getTinySerializationInformation method.
2869  */
2870 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
2871 {
2872   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
2873   if(tinyInfo[5]!=-1)
2874     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
2875 }
2876
2877 /*!
2878  * Third and final step of serialization process.
2879  */
2880 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
2881 {
2882   MEDCouplingPointSet::serialize(a1,a2);
2883   if(getMeshDimension()>-1)
2884     {
2885       a1=DataArrayInt::New();
2886       a1->alloc(getMeshLength()+getNumberOfCells()+1,1);
2887       int *ptA1=a1->getPointer();
2888       const int *conn=getNodalConnectivity()->getConstPointer();
2889       const int *index=getNodalConnectivityIndex()->getConstPointer();
2890       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
2891       std::copy(conn,conn+getMeshLength(),ptA1);
2892     }
2893   else
2894     a1=0;
2895 }
2896
2897 /*!
2898  * Second and final unserialization process.
2899  * @param tinyInfo must be equal to the result given by getTinySerializationInformation method.
2900  */
2901 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
2902 {
2903   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
2904   setMeshDimension(tinyInfo[5]);
2905   if(tinyInfo[7]!=-1)
2906     {
2907       // Connectivity
2908       const int *recvBuffer=a1->getConstPointer();
2909       DataArrayInt* myConnecIndex=DataArrayInt::New();
2910       myConnecIndex->alloc(tinyInfo[6]+1,1);
2911       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
2912       DataArrayInt* myConnec=DataArrayInt::New();
2913       myConnec->alloc(tinyInfo[7],1);
2914       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
2915       setConnectivity(myConnec, myConnecIndex) ;
2916       myConnec->decrRef();
2917       myConnecIndex->decrRef();
2918     }
2919 }
2920
2921 /*!
2922  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf2.
2923  * CellIds are given using range specified by a start an end and step.
2924  */
2925 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords2(int start, int end, int step) const
2926 {
2927   checkFullyDefined();
2928   int ncell=getNumberOfCells();
2929   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2930   ret->_mesh_dim=_mesh_dim;
2931   ret->setCoords(_coords);
2932   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : ");
2933   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
2934   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
2935   int work=start;
2936   const int *conn=_nodal_connec->getConstPointer();
2937   const int *connIndex=_nodal_connec_index->getConstPointer();
2938   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
2939     {
2940       if(work>=0 && work<ncell)
2941         {
2942           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
2943         }
2944       else
2945         {
2946           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
2947           throw INTERP_KERNEL::Exception(oss.str().c_str());
2948         }
2949     }
2950   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
2951   int *newConnPtr=newConn->getPointer();
2952   std::set<INTERP_KERNEL::NormalizedCellType> types;
2953   work=start;
2954   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
2955     {
2956       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
2957       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
2958     }
2959   ret->setConnectivity(newConn,newConnI,false);
2960   ret->_types=types;
2961   ret->copyTinyInfoFrom(this);
2962   return ret.retn();
2963 }
2964
2965 /*!
2966  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
2967  * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
2968  * The return newly allocated mesh will share the same coordinates as 'this'.
2969  */
2970 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
2971 {
2972   checkFullyDefined();
2973   int ncell=getNumberOfCells();
2974   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2975   ret->_mesh_dim=_mesh_dim;
2976   ret->setCoords(_coords);
2977   std::size_t nbOfElemsRet=std::distance(begin,end);
2978   int *connIndexRet=new int[nbOfElemsRet+1];
2979   connIndexRet[0]=0;
2980   const int *conn=_nodal_connec->getConstPointer();
2981   const int *connIndex=_nodal_connec_index->getConstPointer();
2982   int newNbring=0;
2983   for(const int *work=begin;work!=end;work++,newNbring++)
2984     {
2985       if(*work>=0 && *work<ncell)
2986         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
2987       else
2988         {
2989           delete [] connIndexRet;
2990           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
2991           throw INTERP_KERNEL::Exception(oss.str().c_str());
2992         }
2993     }
2994   int *connRet=new int[connIndexRet[nbOfElemsRet]];
2995   int *connRetWork=connRet;
2996   std::set<INTERP_KERNEL::NormalizedCellType> types;
2997   for(const int *work=begin;work!=end;work++)
2998     {
2999       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3000       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3001     }
3002   DataArrayInt *connRetArr=DataArrayInt::New();
3003   connRetArr->useArray(connRet,true,CPP_DEALLOC,connIndexRet[nbOfElemsRet],1);
3004   DataArrayInt *connIndexRetArr=DataArrayInt::New();
3005   connIndexRetArr->useArray(connIndexRet,true,CPP_DEALLOC,(int)nbOfElemsRet+1,1);
3006   ret->setConnectivity(connRetArr,connIndexRetArr,false);
3007   ret->_types=types;
3008   connRetArr->decrRef();
3009   connIndexRetArr->decrRef();
3010   ret->copyTinyInfoFrom(this);
3011   return ret.retn();
3012 }
3013
3014 /*!
3015  * brief returns the volumes of the cells underlying the field \a field
3016  *
3017  * For 2D geometries, the returned field contains the areas.
3018  * For 3D geometries, the returned field contains the volumes.
3019  *
3020  * param field field on which cells the volumes are required
3021  * return field containing the volumes, area or length depending the meshdimension.
3022  */
3023 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3024 {
3025   std::string name="MeasureOfMesh_";
3026   name+=getName();
3027   int nbelem=getNumberOfCells();
3028   MEDCouplingFieldDouble *field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3029   field->setName(name.c_str());
3030   DataArrayDouble* array=DataArrayDouble::New();
3031   array->alloc(nbelem,1);
3032   double *area_vol=array->getPointer();
3033   field->setArray(array) ;
3034   array->decrRef();
3035   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3036   field->synchronizeTimeWithMesh();
3037   if(getMeshDimension()!=-1)
3038     {
3039       int ipt;
3040       INTERP_KERNEL::NormalizedCellType type;
3041       int dim_space=getSpaceDimension();
3042       const double *coords=getCoords()->getConstPointer();
3043       const int *connec=getNodalConnectivity()->getConstPointer();
3044       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3045       for(int iel=0;iel<nbelem;iel++)
3046         {
3047           ipt=connec_index[iel];
3048           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3049           area_vol[iel]=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space);
3050         }
3051       if(isAbs)
3052         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3053     }
3054   else
3055     {
3056       area_vol[0]=std::numeric_limits<double>::max();
3057     }
3058   return field;
3059 }
3060
3061 /*!
3062  * This method is equivalent to MEDCouplingUMesh::getMeasureField except that only part defined by [begin,end) is returned !
3063  * This method avoids to build explicitely part of this to perform the work.
3064  */
3065 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3066 {
3067   std::string name="PartMeasureOfMesh_";
3068   name+=getName();
3069   int nbelem=(int)std::distance(begin,end);
3070   DataArrayDouble* array=DataArrayDouble::New();
3071   array->setName(name.c_str());
3072   array->alloc(nbelem,1);
3073   double *area_vol=array->getPointer();
3074   if(getMeshDimension()!=-1)
3075     {
3076       int ipt;
3077       INTERP_KERNEL::NormalizedCellType type;
3078       int dim_space=getSpaceDimension();
3079       const double *coords=getCoords()->getConstPointer();
3080       const int *connec=getNodalConnectivity()->getConstPointer();
3081       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3082       for(const int *iel=begin;iel!=end;iel++)
3083         {
3084           ipt=connec_index[*iel];
3085           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3086           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3087         }
3088       if(isAbs)
3089         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3090     }
3091   else
3092     {
3093       area_vol[0]=std::numeric_limits<double>::max();
3094     }
3095   return array;
3096 }
3097
3098 /*!
3099  * This methods returns a field on nodes and no time. This method is usefull to check "P1*" conservative interpolators.
3100  * This field returns the getMeasureField of the dualMesh in P1 sens of 'this'.
3101  */
3102 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3103 {
3104   MEDCouplingFieldDouble *tmp=getMeasureField(isAbs);
3105   std::string name="MeasureOnNodeOfMesh_";
3106   name+=getName();
3107   int nbNodes=getNumberOfNodes();
3108   MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_NODES);
3109   double cst=1./((double)getMeshDimension()+1.);
3110   DataArrayDouble* array=DataArrayDouble::New();
3111   array->alloc(nbNodes,1);
3112   double *valsToFill=array->getPointer();
3113   std::fill(valsToFill,valsToFill+nbNodes,0.);
3114   const double *values=tmp->getArray()->getConstPointer();
3115   DataArrayInt *da=DataArrayInt::New();
3116   DataArrayInt *daInd=DataArrayInt::New();
3117   getReverseNodalConnectivity(da,daInd);
3118   const int *daPtr=da->getConstPointer();
3119   const int *daIPtr=daInd->getConstPointer();
3120   for(int i=0;i<nbNodes;i++)
3121     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3122       valsToFill[i]+=cst*values[*cell];
3123   ret->setMesh(this);
3124   da->decrRef();
3125   daInd->decrRef();
3126   ret->setArray(array);
3127   array->decrRef();
3128   tmp->decrRef();
3129   return ret;
3130 }
3131
3132 /*!
3133  * This methods returns a vector field on cells that represents the orthogonal vector normalized of each 2D cell of this.
3134  * This method is only callable on mesh with meshdim == 2 and spacedim==2 or 3.
3135  */
3136 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3137 {
3138   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3139     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3140   MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3141   DataArrayDouble *array=DataArrayDouble::New();
3142   int nbOfCells=getNumberOfCells();
3143   int nbComp=getMeshDimension()+1;
3144   array->alloc(nbOfCells,nbComp);
3145   double *vals=array->getPointer();
3146   const int *connI=_nodal_connec_index->getConstPointer();
3147   const int *conn=_nodal_connec->getConstPointer();
3148   const double *coords=_coords->getConstPointer();
3149   if(getMeshDimension()==2)
3150     {
3151       if(getSpaceDimension()==3)
3152         {
3153           DataArrayDouble *loc=getBarycenterAndOwner();
3154           const double *locPtr=loc->getConstPointer();
3155           for(int i=0;i<nbOfCells;i++,vals+=3)
3156             {
3157               int offset=connI[i];
3158               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3159               double n=INTERP_KERNEL::norm<3>(vals);
3160               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3161             }
3162           loc->decrRef();
3163         }
3164       else
3165         {
3166           for(int i=0;i<nbOfCells;i++)
3167             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3168         }
3169     }
3170   else//meshdimension==1
3171     {
3172       double tmp[2];
3173       for(int i=0;i<nbOfCells;i++)
3174         {
3175           int offset=connI[i];
3176           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3177           double n=INTERP_KERNEL::norm<2>(tmp);
3178           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3179           *vals++=-tmp[1];
3180           *vals++=tmp[0];
3181         }
3182     }
3183   ret->setArray(array);
3184   array->decrRef();
3185   ret->setMesh(this);
3186   ret->synchronizeTimeWithSupport();
3187   return ret;
3188 }
3189
3190 /*!
3191  * This method is equivalent to MEDCouplingUMesh::buildOrthogonalField except that only part defined by [begin,end) is returned !
3192  * This method avoids to build explicitely part of this to perform the work.
3193  */
3194 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3195 {
3196   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3197     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3198   MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3199   DataArrayDouble *array=DataArrayDouble::New();
3200   std::size_t nbelems=std::distance(begin,end);
3201   int nbComp=getMeshDimension()+1;
3202   array->alloc((int)nbelems,nbComp);
3203   double *vals=array->getPointer();
3204   const int *connI=_nodal_connec_index->getConstPointer();
3205   const int *conn=_nodal_connec->getConstPointer();
3206   const double *coords=_coords->getConstPointer();
3207   if(getMeshDimension()==2)
3208     {
3209       if(getSpaceDimension()==3)
3210         {
3211           DataArrayDouble *loc=getPartBarycenterAndOwner(begin,end);
3212           const double *locPtr=loc->getConstPointer();
3213           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3214             {
3215               int offset=connI[*i];
3216               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3217               double n=INTERP_KERNEL::norm<3>(vals);
3218               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3219             }
3220           loc->decrRef();
3221         }
3222       else
3223         {
3224           for(std::size_t i=0;i<nbelems;i++)
3225             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3226         }
3227     }
3228   else//meshdimension==1
3229     {
3230       double tmp[2];
3231       for(const int *i=begin;i!=end;i++)
3232         {
3233           int offset=connI[*i];
3234           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3235           double n=INTERP_KERNEL::norm<2>(tmp);
3236           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3237           *vals++=-tmp[1];
3238           *vals++=tmp[0];
3239         }
3240     }
3241   ret->setArray(array);
3242   array->decrRef();
3243   ret->setMesh(this);
3244   ret->synchronizeTimeWithSupport();
3245   return ret;
3246 }
3247
3248 /*!
3249  * This methods returns a vector newly created field on cells that represents the direction vector of each 1D cell of this.
3250  * This method is only callable on mesh with meshdim == 1 containing only SEG2.
3251  */
3252 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3253 {
3254    if(getMeshDimension()!=1)
3255     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3256    if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3257      throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3258    MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3259    DataArrayDouble *array=DataArrayDouble::New();
3260    int nbOfCells=getNumberOfCells();
3261    int spaceDim=getSpaceDimension();
3262    array->alloc(nbOfCells,spaceDim);
3263    double *pt=array->getPointer();
3264    const double *coo=getCoords()->getConstPointer();
3265    std::vector<int> conn;
3266    conn.reserve(2);
3267    for(int i=0;i<nbOfCells;i++)
3268      {
3269        conn.resize(0);
3270        getNodeIdsOfCell(i,conn);
3271        pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3272      }
3273    ret->setArray(array);
3274    array->decrRef();
3275    ret->setMesh(this);
3276    ret->synchronizeTimeWithSupport();
3277    return ret;   
3278 }
3279
3280 /*!
3281  * This method expects that 'this' is fully defined and has a spaceDim==3 and a meshDim==3. If it is not the case an exception will be thrown.
3282  * This method returns 2 objects : 
3283  * - a newly created mesh instance containing the result of the slice lying on different coords than 'this' and with a meshdim == 2
3284  * - a newly created dataarray having number of tuples equal to the number of cells in returned mesh that tells for each 2D cell in returned
3285  *   mesh the 3D cell id is 'this' it comes from.
3286  * This method works only for linear meshes (non quadratic).
3287  * If plane crosses within 'eps' a face in 'this' shared by more than 1 cell, 2 output faces will be generated. The 2 faces having the same geometry than intersecting
3288  * face. Only 'cellIds' parameter can distinguish the 2.
3289  * @param origin is the origin of the plane. It should be an array of length 3.
3290  * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3291  * @param eps is the precision. It is used by called method MEDCouplingUMesh::getCellIdsCrossingPlane for the first 3D cell selection (in absolute). 'eps' is
3292  * also used to state if new points should be created or already existing points are reused. 'eps' is also used to tells if plane overlaps a face, edge or nodes (in absolute).
3293  */
3294 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const throw(INTERP_KERNEL::Exception)
3295 {
3296   checkFullyDefined();
3297   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3299   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3300   if(candidates->empty())
3301     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3302   std::vector<int> nodes;
3303   DataArrayInt *cellIds1D=0;
3304   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3305   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3306   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3307   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3308   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3309   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3310   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3311   revDesc2=0; revDescIndx2=0;
3312   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3313   revDesc1=0; revDescIndx1=0;
3314   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3315   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIds1DTmp(cellIds1D);
3316   //
3317   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3318   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3319     cut3DCurve[*it]=-1;
3320   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3321   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3322   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3323                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3324                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3325   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3326   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3327   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3328   if(cellIds2->empty())
3329     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3330   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3331   ret->setCoords(mDesc1->getCoords());
3332   ret->setConnectivity(conn,connI,true);
3333   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3334   return ret.retn();
3335 }
3336
3337 /*!
3338  * This method expects that 'this' is fully defined and has a spaceDim==3 and a meshDim==2. If it is not the case an exception will be thrown.
3339  * This method returns 2 objects : 
3340  * - a newly created mesh instance containing the result of the slice lying on different coords than 'this' and with a meshdim == 1
3341  * - a newly created dataarray having number of tuples equal to the number of cells in returned mesh that tells for each 2D cell in returned
3342  *   mesh the 3DSurf cell id is 'this' it comes from.
3343  * This method works only for linear meshes (non quadratic).
3344  * If plane crosses within 'eps' a face in 'this' shared by more than 1 cell, 2 output faces will be generated. The 2 faces having the same geometry than intersecting
3345  * face. Only 'cellIds' parameter can distinguish the 2.
3346  * @param origin is the origin of the plane. It should be an array of length 3.
3347  * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3348  * @param eps is the precision. It is used by called method MEDCouplingUMesh::getCellIdsCrossingPlane for the first 3DSurf cell selection (in absolute). 'eps' is
3349  * also used to state if new points should be created or already existing points are reused. 'eps' is also used to tells if plane overlaps a face, edge or nodes (in absolute).
3350  */
3351 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const throw(INTERP_KERNEL::Exception)
3352 {
3353   checkFullyDefined();
3354   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3355     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3356   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3357   if(candidates->empty())
3358     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3359   std::vector<int> nodes;
3360   DataArrayInt *cellIds1D=0;
3361   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3362   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3363   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New();
3364   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New();
3365   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New();
3366   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New();
3367   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3368   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3369   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIds1DTmp(cellIds1D);
3370   //
3371   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3372   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3373     cut3DCurve[*it]=-1;
3374   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3375   int ncellsSub=subMesh->getNumberOfCells();
3376   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3377   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3378                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3379                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3380   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3381   conn->alloc(0,1);
3382   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3383   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3384   for(int i=0;i<ncellsSub;i++)
3385     {
3386       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3387         {
3388           if(cut3DSurf[i].first!=-2)
3389             {
3390               conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3391               connI->pushBackSilent(conn->getNumberOfTuples());
3392               cellIds2->pushBackSilent(i);
3393             }
3394           else
3395             {
3396               int cellId3DSurf=cut3DSurf[i].second;
3397               int offset=nodalI[cellId3DSurf]+1;
3398               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3399               for(int j=0;j<nbOfEdges;j++)
3400                 {
3401                   conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3402                   connI->pushBackSilent(conn->getNumberOfTuples());
3403                   cellIds2->pushBackSilent(cellId3DSurf);
3404                 }
3405             }
3406         }
3407     }
3408   if(cellIds2->empty())
3409     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3410   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3411   ret->setCoords(mDesc1->getCoords());
3412   ret->setConnectivity(conn,connI,true);
3413   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3414   return ret.retn();
3415 }
3416
3417 /*!
3418  * This method expects that 'this' is fully defined and has a spaceDim==3. If it is not the case an exception will be thrown.
3419  * This method returns a newly created dataarray containing cellsids in 'this' that potentially crosses the plane specified by 'origin' and 'vec'.
3420  * @param origin is the origin of the plane. It should be an array of length 3.
3421  * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3422  */
3423 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const throw(INTERP_KERNEL::Exception)
3424 {
3425   checkFullyDefined();
3426   if(getSpaceDimension()!=3)
3427     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3428   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3429   if(normm<1e-6)
3430     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3431   double vec2[3];
3432   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3433   double angle=acos(vec[2]/normm);
3434   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIds;
3435   double bbox[6];
3436   if(angle>eps)
3437     {
3438       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=_coords->deepCpy();
3439       MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3440       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3441       mw->setCoords(coo);
3442       mw->getBoundingBox(bbox);
3443       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3444       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3445     }
3446   else
3447     {
3448       getBoundingBox(bbox);
3449       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3450       cellIds=getCellsInBoundingBox(bbox,eps);
3451     }
3452   return cellIds.retn();
3453 }
3454
3455 /*!
3456  * This method checks that 'this' is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3457  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3458  * No consideration of coordinate is done by this method.
3459  * A 1D mesh is said contiguous if : a cell i with nodal connectivity (k,p) the cell i+1 the nodal connectivity should be (p,m)
3460  * If not false is returned. In case that false is returned a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes could be usefull.
3461  */
3462 bool MEDCouplingUMesh::isContiguous1D() const throw(INTERP_KERNEL::Exception)
3463 {
3464   if(getMeshDimension()!=1)
3465     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3466   int nbCells=getNumberOfCells();
3467   if(nbCells<1)
3468     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3469   const int *connI=_nodal_connec_index->getConstPointer();
3470   const int *conn=_nodal_connec->getConstPointer();
3471   int ref=conn[connI[0]+2];
3472   for(int i=1;i<nbCells;i++)
3473     {
3474       if(conn[connI[i]+1]!=ref)
3475         return false;
3476       ref=conn[connI[i]+2];
3477     }
3478   return true;
3479 }
3480
3481 /*!
3482  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3483  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3484  * @param pt reference point of the line
3485  * @param v normalized director vector of the line
3486  * @param eps max precision before throwing an exception
3487  * @param res output of size this->getNumberOfCells
3488  */
3489 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3490 {
3491   if(getMeshDimension()!=1)
3492     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3493    if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3494      throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3495    if(getSpaceDimension()!=3)
3496      throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3497    MEDCouplingFieldDouble *f=buildDirectionVectorField();
3498    const double *fPtr=f->getArray()->getConstPointer();
3499    double tmp[3];
3500    for(int i=0;i<getNumberOfCells();i++)
3501      {
3502        const double *tmp1=fPtr+3*i;
3503        tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3504        tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3505        tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3506        double n1=INTERP_KERNEL::norm<3>(tmp);
3507        n1/=INTERP_KERNEL::norm<3>(tmp1);
3508        if(n1>eps)
3509          {
3510            f->decrRef();
3511            throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3512          }
3513      }
3514    const double *coo=getCoords()->getConstPointer();
3515    for(int i=0;i<getNumberOfNodes();i++)
3516      {
3517        std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3518        std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3519        res[i]=std::accumulate(tmp,tmp+3,0.);
3520      }
3521    f->decrRef();
3522 }
3523
3524 /*!
3525  * This method computes the distance from a point \a pt to \a this and the first \a cellId and \a nodeId in \a this corresponding to the returned distance. 
3526  * \a this is expected to be a mesh so that its space dimension is equal to its
3527  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3528  * Distance from \a ptBg to \a ptEnd is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates).
3529  * 
3530  * This method firstly find the closer node in \a this to the requested point whose coordinates are defined by [ \a ptBg, \a ptEnd ). Then for this node found 
3531  * the cells sharing this node (if any) are considered to find if the distance to these cell are smaller than the result found previously. If no cells are linked
3532  * to the node that minimizes distance with the input point then -1 is returned in cellId.
3533  *
3534  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3535  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3536  *
3537  * \param [in] ptBg the start pointer (included) of the coordinates of the point
3538  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3539  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3540  * \return the positive value of the distance.
3541  * \throw if distance from \a ptBg to \a ptEnd is not equal to the space dimension. An exception is also thrown if mesh dimension of \a this is not equal to space
3542  * dimension - 1.
3543  * \sa DataArrayDouble::distanceToTuple
3544  */
3545 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId, int& nodeId) const throw(INTERP_KERNEL::Exception)
3546 {
3547   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3548   if(meshDim!=spaceDim-1)
3549     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3550   if(meshDim!=2 && meshDim!=1)
3551     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3552   checkFullyDefined();
3553   if((int)std::distance(ptBg,ptEnd)!=spaceDim)
3554     { std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoint : input point has to have dimension equal to the space dimension of this (" << spaceDim << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
3555   nodeId=-1;
3556   double ret0=_coords->distanceToTuple(ptBg,ptEnd,nodeId);
3557   if(nodeId==-1)
3558     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : something wrong with nodes in this !");
3559   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIds=getCellIdsLyingOnNodes(&nodeId,&nodeId+1,false);
3560   switch(meshDim)
3561     {
3562     case 2:
3563       {
3564         distanceToPoint3DSurfAlg(ptBg,cellIds,ret0,cellId);
3565         return ret0;
3566       }
3567     case 1:
3568       {
3569         distanceToPoint2DCurveAlg(ptBg,cellIds,ret0,cellId);
3570         return ret0;
3571       }
3572     default:
3573       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3574     }
3575   
3576   return ret0;
3577 }
3578
3579
3580 /*!
3581  * \param [in] pt the start pointer (included) of the coordinates of the point
3582  * \param [in] cellIds
3583  * \param [in,out] ret0 the min distance between \a this and the external input point
3584  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3585  * \sa MEDCouplingUMesh::distanceToPoint
3586  */
3587 void MEDCouplingUMesh::distanceToPoint3DSurfAlg(const double *pt, const DataArrayInt *cellIds, double& ret0, int& cellId) const throw(INTERP_KERNEL::Exception)
3588 {
3589   const double *coords=_coords->getConstPointer();
3590   cellId=-1; 
3591   if(cellIds->empty())
3592     return;
3593   const int *ptr=_nodal_connec->getConstPointer();
3594   const int *ptrI=_nodal_connec_index->getConstPointer();
3595   for(const int *zeCell=cellIds->begin();zeCell!=cellIds->end();zeCell++)
3596     {
3597       switch((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[*zeCell]])
3598         {
3599         case INTERP_KERNEL::NORM_TRI3:
3600           {
3601             double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*ptr[ptrI[*zeCell]+1],coords+3*ptr[ptrI[*zeCell]+2],coords+3*ptr[ptrI[*zeCell]+3]);
3602             if(tmp<ret0)
3603               { ret0=tmp; cellId=*zeCell; }
3604             break;
3605           }
3606         case INTERP_KERNEL::NORM_QUAD4:
3607         case INTERP_KERNEL::NORM_POLYGON:
3608           {
3609             double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,ptr+ptrI[*zeCell]+1,ptr+ptrI[*zeCell+1],coords);
3610             if(tmp<ret0)
3611               { ret0=tmp; cellId=*zeCell; }
3612             break;
3613           }
3614         default:
3615           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
3616         }
3617     }
3618 }
3619
3620 /*!
3621  * \param [in] pt the start pointer (included) of the coordinates of the point
3622  * \param [in] cellIds
3623  * \param [in,out] ret0 the min distance between \a this and the external input point
3624  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3625  * \sa MEDCouplingUMesh::distanceToPoint
3626  */
3627 void MEDCouplingUMesh::distanceToPoint2DCurveAlg(const double *pt, const DataArrayInt *cellIds, double& ret0, int& cellId) const throw(INTERP_KERNEL::Exception)
3628 {
3629   const double *coords=_coords->getConstPointer();
3630   if(cellIds->empty())
3631     { cellId=-1; return; }
3632   const int *ptr=_nodal_connec->getConstPointer();
3633   const int *ptrI=_nodal_connec_index->getConstPointer();
3634   for(const int *zeCell=cellIds->begin();zeCell!=cellIds->end();zeCell++)
3635     {
3636        switch((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[*zeCell]])
3637         {
3638         case INTERP_KERNEL::NORM_SEG2:
3639           {
3640             double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*ptr[ptrI[*zeCell]+1],coords+2*ptr[ptrI[*zeCell]+2]);
3641             if(tmp!=std::numeric_limits<double>::max()) tmp=sqrt(tmp);
3642             if(tmp<ret0)
3643               { ret0=tmp; cellId=*zeCell; }
3644             break;
3645           }
3646         default:
3647           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
3648         }
3649     }
3650 }
3651
3652 /*!
3653  * Returns a cell if any that contains the point located on 'pos' with precison eps.
3654  * If 'pos' is outside 'this' -1 is returned. If several cells contain this point the cell with the smallest id is returned.
3655  * \b Warning this method is good if the caller intends to evaluate only one point. But if more than one point is requested on 'this'
3656  * it is better to use MEDCouplingUMesh::getCellsContainingPoints method because in this case, the acceleration structure will be computed only once.
3657  */
3658 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
3659 {
3660   std::vector<int> elts;
3661   getCellsContainingPoint(pos,eps,elts);
3662   if(elts.empty())
3663     return -1;
3664   return elts.front();
3665 }
3666
3667 /*!
3668  * Returns all cellIds in 'elts' of point 'pos' with eps accuracy.
3669  * \b Warning this method is good if the caller intends to evaluate only one point. But if more than one point is requested on 'this'
3670  * it is better to use MEDCouplingUMesh::getCellsContainingPoints method because in this case, the acceleration structure will be computed only once.
3671  */
3672 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
3673 {
3674   std::vector<int> eltsIndex;
3675   getCellsContainingPoints(pos,1,eps,elts,eltsIndex);
3676 }
3677
3678 /// @cond INTERNAL
3679
3680 namespace ParaMEDMEM
3681 {
3682   template<const int SPACEDIMM>
3683   class DummyClsMCUG
3684   {
3685   public:
3686     static const int MY_SPACEDIM=SPACEDIMM;
3687     static const int MY_MESHDIM=8;
3688     typedef int MyConnType;
3689     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
3690     // begin
3691     // useless, but for windows compilation ...
3692     const double* getCoordinatesPtr() const { return 0; }
3693     const int* getConnectivityPtr() const { return 0; }
3694     const int* getConnectivityIndexPtr() const { return 0; }
3695     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
3696     // end
3697   };
3698
3699   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
3700   {
3701     INTERP_KERNEL::Edge *ret=0;
3702     switch(typ)
3703       {
3704       case INTERP_KERNEL::NORM_SEG2:
3705         {
3706           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
3707           break;
3708         }
3709       case INTERP_KERNEL::NORM_SEG3:
3710         {
3711           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
3712           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
3713           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
3714           bool colinearity=inters.areColinears();
3715           delete e1; delete e2;
3716           if(colinearity)
3717             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
3718           else
3719             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
3720           mapp2[bg[2]].second=false;
3721           break;
3722         }
3723       default:
3724         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
3725       }
3726     return ret;
3727   }
3728
3729   /*!
3730    * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed be the sub set of cells in 'candidates' and the global mesh 'mDesc'.
3731    * The input meth 'mDesc' must be so that mDim==1 et spaceDim==3.
3732    * 'mapp' contains a mapping between local numbering in submesh and the global node numbering in 'mDesc'.
3733    */
3734   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates, std::map<INTERP_KERNEL::Node *,int>& mapp) throw(INTERP_KERNEL::Exception)
3735   {
3736     mapp.clear();
3737     std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;//bool is for a flag specifying if node is boundary (true) or only a middle for SEG3.
3738     const double *coo=mDesc->getCoords()->getConstPointer();
3739     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
3740     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
3741     std::set<int> s;
3742     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
3743       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
3744     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
3745       {
3746         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
3747         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
3748       }
3749     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
3750     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
3751       {
3752         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
3753         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
3754       }
3755     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
3756       {
3757         if((*it2).second.second)
3758           mapp[(*it2).second.first]=(*it2).first;
3759         ((*it2).second.first)->decrRef();
3760       }
3761     return ret;
3762   }
3763
3764   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
3765   {
3766     if(nodeId>=offset2)
3767       {
3768         int locId=nodeId-offset2;
3769         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
3770       }
3771     if(nodeId>=offset1)
3772       {
3773         int locId=nodeId-offset1;
3774         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
3775       }
3776     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
3777   }
3778
3779   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
3780                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
3781                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
3782   {
3783     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
3784       {
3785         int eltId1=abs(*desc1)-1;
3786         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
3787           {
3788             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
3789             if(it==mappRev.end())
3790               {
3791                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
3792                 mapp[node]=*it1;
3793                 mappRev[*it1]=node;
3794               }
3795           }
3796       }
3797   }
3798 }
3799
3800 /// @endcond
3801
3802 template<int SPACEDIM>
3803 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
3804                                                    double eps, std::vector<int>& elts, std::vector<int>& eltsIndex) const
3805 {
3806   std::vector<double> bbox;
3807   eltsIndex.resize(nbOfPoints+1);
3808   eltsIndex[0]=0;
3809   elts.clear();
3810   getBoundingBoxForBBTree(bbox);
3811   int nbOfCells=getNumberOfCells();
3812   const int *conn=_nodal_connec->getConstPointer();
3813   const int *connI=_nodal_connec_index->getConstPointer();
3814   double bb[2*SPACEDIM];
3815   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
3816   for(int i=0;i<nbOfPoints;i++)
3817     {
3818       eltsIndex[i+1]=eltsIndex[i];
3819       for(int j=0;j<SPACEDIM;j++)
3820         {
3821           bb[2*j]=pos[SPACEDIM*i+j];
3822           bb[2*j+1]=pos[SPACEDIM*i+j];
3823         }
3824       std::vector<int> candidates;
3825       myTree.getIntersectingElems(bb,candidates);
3826       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
3827         {
3828           int sz=connI[(*iter)+1]-connI[*iter]-1;
3829           if(INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,
3830                                                                                                (INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]],
3831                                                                                                coords,conn+connI[*iter]+1,sz,eps))
3832             {
3833               eltsIndex[i+1]++;
3834               elts.push_back(*iter);
3835             }
3836         }
3837     }
3838 }
3839
3840 /*!
3841  * This method is an extension of MEDCouplingUMesh::getCellContainingPoint and MEDCouplingUMesh::getCellsContainingPoint.
3842  * This method performs 'nbOfPoints' time the getCellsContainingPoint request. This method is recommended rather than the 2 others
3843  * in case of multi points searching.
3844  * This method returns 2 arrays 'elts' and 'eltsIndex'. 'eltsIndex' is of size 'nbOfPoints+1' and 'elts' is of size 'eltsIndex[nbOfPoints-1]'.
3845  * For point j in [0,nbOfPoints), (eltsIndex[j+1]-eltsIndex[j]) cells contain this point. These cells are : [elts.begin()+eltsIndex[j],elts.begin():eltsIndex[j+1]).
3846  * 
3847  * \param pos input parameter that points to an array of size 'getSpaceDim()*nbOfPoints' points stored in full interlace mode : X0,Y0,Z0,X1,Y1,Z1...
3848  */
3849 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
3850                                                 std::vector<int>& elts, std::vector<int>& eltsIndex) const
3851 {
3852   int spaceDim=getSpaceDimension();
3853   int mDim=getMeshDimension();
3854   if(spaceDim==3)
3855     {
3856       if(mDim==3)
3857         {
3858           const double *coords=_coords->getConstPointer();
3859           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3860         }
3861       /*else if(mDim==2)
3862         {
3863           
3864         }*/
3865       else
3866         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
3867     }
3868   else if(spaceDim==2)
3869     {
3870       if(mDim==2)
3871         {
3872           const double *coords=_coords->getConstPointer();
3873           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3874         }
3875       else
3876         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
3877     }
3878   else if(spaceDim==1)
3879     {
3880       if(mDim==1)
3881         {
3882           const double *coords=_coords->getConstPointer();
3883           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3884         }
3885       else
3886         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
3887     }
3888   else
3889     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
3890 }
3891
3892 /*!
3893  * This method is only available for a mesh with meshDim==2 and spaceDim==2||spaceDim==3.
3894  * This method returns a vector 'cells' where all detected butterfly cells have been added to cells.
3895  * A 2D cell is considered to be butterfly if it exists at least one pair of distinct edges of it that intersect each other
3896  * anywhere excepted their extremities. An INTERP_KERNEL::NORM_NORI3 could \b not be butterfly.
3897  */
3898 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
3899 {
3900   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
3901   if(getMeshDimension()!=2)
3902     throw INTERP_KERNEL::Exception(msg);
3903   int spaceDim=getSpaceDimension();
3904   if(spaceDim!=2 && spaceDim!=3)
3905     throw INTERP_KERNEL::Exception(msg);
3906   const int *conn=_nodal_connec->getConstPointer();
3907   const int *connI=_nodal_connec_index->getConstPointer();
3908   int nbOfCells=getNumberOfCells();
3909   std::vector<double> cell2DinS2;
3910   for(int i=0;i<nbOfCells;i++)
3911     {
3912       int offset=connI[i];
3913       int nbOfNodesForCell=connI[i+1]-offset-1;
3914       if(nbOfNodesForCell<=3)
3915         continue;
3916       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
3917       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
3918       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
3919         cells.push_back(i);
3920       cell2DinS2.clear();
3921     }
3922 }
3923
3924 /*!
3925  * This method is typically requested to unbutterfly 2D linear cells in \b this.
3926  *
3927  * This method expects that space dimension is equal to 2 and mesh dimension is equal to 2 too. If it is not the case an INTERP_KERNEL::Exception will be thrown.
3928  * This method works only for linear 2D cells. If there is any of non linear cells (INTERP_KERNEL::NORM_QUAD8 for example) an INTERP_KERNEL::Exception will be thrown too.
3929  * 
3930  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
3931  * This convex envelop is computed using Jarvis march algorithm.
3932  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
3933  * Only connectivity of some cells could be modified if those cells were not representing a convex envelop. If a cell already equals its convex envelop (regardless orientation)
3934  * its connectivity will remain unchanged. If the computation leads to a modification of nodal connectivity of a cell its geometric type will be modified to INTERP_KERNEL::NORM_POLYGON.
3935  *
3936  * @return a newly allocated array containing cellIds that have been modified if any. If no cells have been impacted by this method NULL is returned.
3937  */
3938 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D() throw(INTERP_KERNEL::Exception)
3939 {
3940   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
3941     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
3942   checkFullyDefined();
3943   const double *coords=getCoords()->getConstPointer();
3944   int nbOfCells=getNumberOfCells();
3945   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
3946   nodalConnecIndexOut->alloc(nbOfCells+1,1);
3947   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodalConnecOut(DataArrayInt::New());
3948   int *workIndexOut=nodalConnecIndexOut->getPointer();
3949   *workIndexOut=0;
3950   const int *nodalConnecIn=_nodal_connec->getConstPointer();
3951   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
3952   std::set<INTERP_KERNEL::NormalizedCellType> types;
3953   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> isChanged(DataArrayInt::New());
3954   isChanged->alloc(0,1);
3955   for(int i=0;i<nbOfCells;i++,workIndexOut++)
3956     {
3957       int pos=nodalConnecOut->getNumberOfTuples();
3958       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
3959         isChanged->pushBackSilent(i);
3960       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
3961       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
3962     }
3963   if(isChanged->empty())
3964     return 0;
3965   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
3966   _types=types;
3967   return isChanged.retn();
3968 }
3969
3970 /*!
3971  * This method is \b NOT const because it can modify 'this'.
3972  * 'this' is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
3973  * @param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
3974  * @param policy specifies the type of extrusion chosen. \b 0 for translation (most simple),
3975  * \b 1 for translation and rotation around point of 'mesh1D'.
3976  * @return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than 'this'.  
3977  */
3978 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
3979 {
3980   checkFullyDefined();
3981   mesh1D->checkFullyDefined();
3982   if(!mesh1D->isContiguous1D())
3983     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
3984   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
3985     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same dimension !");
3986   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3987     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
3988   if(mesh1D->getMeshDimension()!=1)
3989     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
3990   bool isQuad=false;
3991   if(isPresenceOfQuadratic())
3992     {
3993       if(mesh1D->isFullyQuadratic())
3994         isQuad=true;
3995       else
3996         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
3997     }
3998   zipCoords();
3999   int oldNbOfNodes=getNumberOfNodes();
4000   DataArrayDouble *newCoords=0;
4001   switch(policy)
4002     {
4003     case 0:
4004       {
4005         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4006         break;
4007       }
4008     case 1:
4009       {
4010         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4011         break;
4012       }
4013     default:
4014       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4015     }
4016   setCoords(newCoords);
4017   newCoords->decrRef();
4018   MEDCouplingUMesh *ret=buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad);
4019   updateTime();
4020   return ret;
4021 }
4022
4023 /*!
4024  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4025  * If it is not the case an exception will be thrown.
4026  * This method is non const because the coordinate of 'this' can be appended with some new points issued from
4027  * intersection of plane defined by ('origin','vec').
4028  * This method has one in/out parameter : 'cut3DCurve'.
4029  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4030  * if cut3DCurve[i]==-2, it means that for cell #i in 'this' nothing has been detected previously.
4031  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4032  * This method will throw an exception if 'this' contains a non linear segment.
4033  */
4034 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve) throw(INTERP_KERNEL::Exception)
4035 {
4036   checkFullyDefined();
4037   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4038     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4039   int ncells=getNumberOfCells();
4040   int nnodes=getNumberOfNodes();
4041   double vec2[3],vec3[3],vec4[3];
4042   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4043   if(normm<1e-6)
4044     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4045   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4046   const int *conn=_nodal_connec->getConstPointer();
4047   const int *connI=_nodal_connec_index->getConstPointer();
4048   const double *coo=_coords->getConstPointer();
4049   std::vector<double> addCoo;
4050   for(int i=0;i<ncells;i++)
4051     {
4052       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4053         {
4054           if(cut3DCurve[i]==-2)
4055             {
4056               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4057               vec3[0]=coo[3*endd]-coo[3*st]; vec3[1]=coo[3*endd+1]-coo[3*st+1]; vec3[2]=coo[3*endd+2]-coo[3*st+2];
4058               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4059               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4060               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4061                 {
4062                   const double *st2=coo+3*st;
4063                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4064                   double pos=-(vec4[0]*vec2[0]+vec4[1]*vec2[1]+vec4[2]*vec2[2])/((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2]));
4065                   if(pos>eps && pos<1-eps)
4066                     {
4067                       int nNode=((int)addCoo.size())/3;
4068                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4069                       addCoo.insert(addCoo.end(),vec4,vec4+3);
4070                       cut3DCurve[i]=nnodes+nNode;
4071                     }
4072                 }
4073             }
4074         }
4075       else
4076         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4077     }
4078   if(!addCoo.empty())
4079     {
4080       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4081       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo2=DataArrayDouble::New();
4082       coo2->alloc(newNbOfNodes,3);
4083       double *tmp=coo2->getPointer();
4084       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4085       std::copy(addCoo.begin(),addCoo.end(),tmp);
4086       DataArrayDouble::SetArrayIn(coo2,_coords);
4087     }
4088 }
4089
4090 /*!
4091  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4092  * @param mesh1D is the input 1D mesh used for translation computation.
4093  * @return newCoords new coords filled by this method. 
4094  */
4095 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4096 {
4097   int oldNbOfNodes=getNumberOfNodes();
4098   int nbOf1DCells=mesh1D->getNumberOfCells();
4099   int spaceDim=getSpaceDimension();
4100   DataArrayDouble *ret=DataArrayDouble::New();
4101   std::vector<bool> isQuads;
4102   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4103   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4104   double *retPtr=ret->getPointer();
4105   const double *coords=getCoords()->getConstPointer();
4106   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4107   std::vector<int> v;
4108   std::vector<double> c;
4109   double vec[3];
4110   v.reserve(3);
4111   c.reserve(6);
4112   for(int i=0;i<nbOf1DCells;i++)
4113     {
4114       v.resize(0);
4115       mesh1D->getNodeIdsOfCell(i,v);
4116       c.resize(0);
4117       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4118       mesh1D->getCoordinatesOfNode(v[0],c);
4119       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4120       for(int j=0;j<oldNbOfNodes;j++)
4121         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4122       if(isQuad)
4123         {
4124           c.resize(0);
4125           mesh1D->getCoordinatesOfNode(v[1],c);
4126           mesh1D->getCoordinatesOfNode(v[0],c);
4127           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4128           for(int j=0;j<oldNbOfNodes;j++)
4129             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4130         }
4131     }
4132   ret->copyStringInfoFrom(*getCoords());
4133   return ret;
4134 }
4135
4136 /*!
4137  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4138  * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4139  * @return newCoords new coords filled by this method. 
4140  */
4141 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4142 {
4143   if(mesh1D->getSpaceDimension()==2)
4144     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4145   if(mesh1D->getSpaceDimension()==3)
4146     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4147   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4148 }
4149
4150 /*!
4151  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4152  * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4153  * @return newCoords new coords filled by this method. 
4154  */
4155 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4156 {
4157   if(isQuad)
4158     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4159   int oldNbOfNodes=getNumberOfNodes();
4160   int nbOf1DCells=mesh1D->getNumberOfCells();
4161   if(nbOf1DCells<2)
4162     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4163   DataArrayDouble *ret=DataArrayDouble::New();
4164   int nbOfLevsInVec=nbOf1DCells+1;
4165   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4166   double *retPtr=ret->getPointer();
4167   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4168   MEDCouplingUMesh *tmp=MEDCouplingUMesh::New();
4169   DataArrayDouble *tmp2=getCoords()->deepCpy();
4170   tmp->setCoords(tmp2);
4171   tmp2->decrRef();
4172   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4173   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4174   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4175   for(int i=1;i<nbOfLevsInVec;i++)
4176     {
4177       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4178       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4179       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4180       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4181       tmp->translate(vec);
4182       double tmp3[2],radius,alpha,alpha0;
4183       const double *p0=i+1<nbOfLevsInVec?begin:third;
4184       const double *p1=i+1<nbOfLevsInVec?end:begin;
4185       const double *p2=i+1<nbOfLevsInVec?third:end;
4186       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4187       double cosangle=i+1<nbOfLevsInVec?(p0[0]-tmp3[0])*(p1[0]-tmp3[0])+(p0[1]-tmp3[1])*(p1[1]-tmp3[1]):(p2[0]-tmp3[0])*(p1[0]-tmp3[0])+(p2[1]-tmp3[1])*(p1[1]-tmp3[1]);
4188       double angle=acos(cosangle/(radius*radius));
4189       tmp->rotate(end,0,angle);
4190       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4191     }
4192   tmp->decrRef();
4193   return ret;
4194 }
4195
4196 /*!
4197  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4198  * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4199  * @return newCoords new coords filled by this method. 
4200  */
4201 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4202 {
4203   if(isQuad)
4204     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4205   int oldNbOfNodes=getNumberOfNodes();
4206   int nbOf1DCells=mesh1D->getNumberOfCells();
4207   if(nbOf1DCells<2)
4208     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4209   DataArrayDouble *ret=DataArrayDouble::New();
4210   int nbOfLevsInVec=nbOf1DCells+1;
4211   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4212   double *retPtr=ret->getPointer();
4213   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4214   MEDCouplingUMesh *tmp=MEDCouplingUMesh::New();
4215   DataArrayDouble *tmp2=getCoords()->deepCpy();
4216   tmp->setCoords(tmp2);
4217   tmp2->decrRef();
4218   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4219   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4220   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4221   for(int i=1;i<nbOfLevsInVec;i++)
4222     {
4223       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4224       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4225       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4226       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4227       tmp->translate(vec);
4228       double tmp3[2],radius,alpha,alpha0;
4229       const double *p0=i+1<nbOfLevsInVec?begin:third;
4230       const double *p1=i+1<nbOfLevsInVec?end:begin;
4231       const double *p2=i+1<nbOfLevsInVec?third:end;
4232       double vecPlane[3]={
4233         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4234         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4235         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4236       };
4237       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4238       if(norm>1.e-7)
4239         {
4240           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4241           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4242           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4243           double s2=norm2;
4244           double c2=cos(asin(s2));
4245           double m[3][3]={
4246             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4247             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4248             {-vec2[1]*s2, vec2[0]*s2, c2}
4249           };
4250           double p0r[3]={m[0][0]*p0[0]+m[0][1]*p0[1]+m[0][2]*p0[2], m[1][0]*p0[0]+m[1][1]*p0[1]+m[1][2]*p0[2], m[2][0]*p0[0]+m[2][1]*p0[1]+m[2][2]*p0[2]};
4251           double p1r[3]={m[0][0]*p1[0]+m[0][1]*p1[1]+m[0][2]*p1[2], m[1][0]*p1[0]+m[1][1]*p1[1]+m[1][2]*p1[2], m[2][0]*p1[0]+m[2][1]*p1[1]+m[2][2]*p1[2]};
4252           double p2r[3]={m[0][0]*p2[0]+m[0][1]*p2[1]+m[0][2]*p2[2], m[1][0]*p2[0]+m[1][1]*p2[1]+m[1][2]*p2[2], m[2][0]*p2[0]+m[2][1]*p2[1]+m[2][2]*p2[2]};
4253           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4254           double cosangle=i+1<nbOfLevsInVec?(p0r[0]-tmp3[0])*(p1r[0]-tmp3[0])+(p0r[1]-tmp3[1])*(p1r[1]-tmp3[1]):(p2r[0]-tmp3[0])*(p1r[0]-tmp3[0])+(p2r[1]-tmp3[1])*(p1r[1]-tmp3[1]);
4255           double angle=acos(cosangle/(radius*radius));
4256           tmp->rotate(end,vecPlane,angle);
4257           
4258         }
4259       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4260     }
4261   tmp->decrRef();
4262   return ret;
4263 }
4264
4265 /*!
4266  * This method is private because not easy to use for end user. This method is const contrary to
4267  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4268  * the coords sorted slice by slice.
4269  * @param isQuad specifies presence of quadratic cells.
4270  */
4271 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4272 {
4273   int nbOf1DCells=getNumberOfNodes()/nbOfNodesOf1Lev-1;
4274   int nbOf2DCells=getNumberOfCells();
4275   int nbOf3DCells=nbOf2DCells*nbOf1DCells;
4276   MEDCouplingUMesh *ret=MEDCouplingUMesh::New("Extruded",getMeshDimension()+1);
4277   const int *conn=_nodal_connec->getConstPointer();
4278   const int *connI=_nodal_connec_index->getConstPointer();
4279   DataArrayInt *newConn=DataArrayInt::New();
4280   DataArrayInt *newConnI=DataArrayInt::New();
4281   newConnI->alloc(nbOf3DCells+1,1);
4282   int *newConnIPtr=newConnI->getPointer();
4283   *newConnIPtr++=0;
4284   std::vector<int> newc;
4285   for(int j=0;j<nbOf2DCells;j++)
4286     {
4287       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
4288       *newConnIPtr++=(int)newc.size();
4289     }
4290   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
4291   int *newConnPtr=newConn->getPointer();
4292   int deltaPerLev=isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev;
4293   newConnIPtr=newConnI->getPointer();
4294   for(int iz=0;iz<nbOf1DCells;iz++)
4295     {
4296       if(iz!=0)
4297         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
4298       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
4299         {
4300           int icell=(int)(iter-newc.begin());
4301           if(std::find(newConnIPtr,newConnIPtr+nbOf2DCells,icell)==newConnIPtr+nbOf2DCells)
4302             {
4303               if(*iter!=-1)
4304                 *newConnPtr=(*iter)+iz*deltaPerLev;
4305               else
4306                 *newConnPtr=-1;
4307             }
4308           else
4309             *newConnPtr=(*iter);
4310         }
4311     }
4312   ret->setConnectivity(newConn,newConnI,true);
4313   newConn->decrRef();
4314   newConnI->decrRef();
4315   ret->setCoords(getCoords());
4316   return ret;
4317 }
4318
4319 /*!
4320  * This method returns if 'this' is constituted by only quadratic cells.
4321  */
4322 bool MEDCouplingUMesh::isFullyQuadratic() const
4323 {
4324   checkFullyDefined();
4325   bool ret=true;
4326   int nbOfCells=getNumberOfCells();
4327   for(int i=0;i<nbOfCells && ret;i++)
4328     {
4329       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4330       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4331       ret=cm.isQuadratic();
4332     }
4333   return ret;
4334 }
4335
4336 /*!
4337  * This method returns if there is at least one quadratic cell.
4338  */
4339 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4340 {
4341   checkFullyDefined();
4342   bool ret=false;
4343   int nbOfCells=getNumberOfCells();
4344   for(int i=0;i<nbOfCells && !ret;i++)
4345     {
4346       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4347       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4348       ret=cm.isQuadratic();
4349     }
4350   return ret;
4351 }
4352
4353 /*!
4354  * This method convert quadratic cells to linear cells if any was found.
4355  * If no such cells exists 'this' remains unchanged.
4356  */
4357 void MEDCouplingUMesh::convertQuadraticCellsToLinear() throw(INTERP_KERNEL::Exception)
4358 {
4359   checkFullyDefined();
4360   int nbOfCells=getNumberOfCells();
4361   int delta=0;
4362   for(int i=0;i<nbOfCells;i++)
4363     {
4364       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4365       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4366       if(cm.isQuadratic())
4367         {
4368           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4369           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4370           delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4371         }
4372     }
4373   if(delta==0)
4374     return ;
4375   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4376   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4377   newConn->alloc(getMeshLength()-delta,1);
4378   newConnI->alloc(nbOfCells+1,1);
4379   const int *icptr=_nodal_connec->getConstPointer();
4380   const int *iciptr=_nodal_connec_index->getConstPointer();
4381   int *ocptr=newConn->getPointer();
4382   int *ociptr=newConnI->getPointer();
4383   *ociptr=0;
4384   _types.clear();
4385   for(int i=0;i<nbOfCells;i++,ociptr++)
4386     {
4387       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4388       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4389       if(!cm.isQuadratic())
4390         {
4391           _types.insert(type);
4392           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4393           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4394         }
4395       else
4396         {
4397           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4398           _types.insert(typel);
4399           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4400           int newNbOfNodes=cml.getNumberOfNodes();
4401           *ocptr++=(int)typel;
4402           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4403           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4404         }
4405     }
4406   setConnectivity(newConn,newConnI,false);
4407 }
4408
4409 /*!
4410  * This method tessallates 'this' so that the number of cells remains the same.
4411  * This method works only for meshes with spaceDim equal to 2 and meshDim equal to 2.
4412  * If no cells are quadratic in 'this' (INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ) this method will remain unchanged.
4413  * 
4414  * \b WARNING this method can lead to a uge amount of nodes if eps is very low.
4415  * @param eps specifies the maximal angle (in radian) between 2 subedges of polylinized edge constituting the input polygon.
4416  */
4417 void MEDCouplingUMesh::tessellate2D(double eps) throw(INTERP_KERNEL::Exception)
4418 {
4419   checkFullyDefined();
4420   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
4421     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
4422   double epsa=fabs(eps);
4423   if(epsa<std::numeric_limits<double>::min())
4424     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
4425   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New();
4426   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New();
4427   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New();
4428   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New();
4429   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc=buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
4430   revDesc1=0; revDescIndx1=0;
4431   mDesc->tessellate2DCurve(eps);
4432   subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
4433   setCoords(mDesc->getCoords());
4434 }
4435
4436 /*!
4437  * This method tessallates 'this' so that the number of cells remains the same.
4438  * This method works only for meshes with spaceDim equal to 2 and meshDim equal to 1.
4439  * If no cells are quadratic in 'this' (INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ) this method will remain unchanged.
4440  * 
4441  * \b WARNING this method can lead to a uge amount of nodes if eps is very low.
4442  * @param eps specifies the maximal angle (in radian) between 2 subedges of polylinized edge constituting the input polygon.
4443  */
4444 void MEDCouplingUMesh::tessellate2DCurve(double eps) throw(INTERP_KERNEL::Exception)
4445 {
4446   checkFullyDefined();
4447   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
4448     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
4449   double epsa=fabs(eps);
4450   if(epsa<std::numeric_limits<double>::min())
4451     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
4452   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
4453   int nbCells=getNumberOfCells();
4454   int nbNodes=getNumberOfNodes();
4455   const int *conn=_nodal_connec->getConstPointer();
4456   const int *connI=_nodal_connec_index->getConstPointer();
4457   const double *coords=_coords->getConstPointer();
4458   std::vector<double> addCoo;
4459   std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
4460   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI(DataArrayInt::New());
4461   newConnI->alloc(nbCells+1,1);
4462   int *newConnIPtr=newConnI->getPointer();
4463   *newConnIPtr=0;
4464   int tmp1[3];
4465   INTERP_KERNEL::Node *tmp2[3];
4466   std::set<INTERP_KERNEL::NormalizedCellType> types;
4467   for(int i=0;i<nbCells;i++,newConnIPtr++)
4468     {
4469       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4470       if(cm.isQuadratic())
4471         {//assert(connI[i+1]-connI[i]-1==3)
4472           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
4473           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
4474           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
4475           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
4476           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
4477           if(eac)
4478             {
4479               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
4480               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
4481               delete eac;
4482               newConnIPtr[1]=(int)newConn.size();
4483             }
4484           else
4485             {
4486               types.insert(INTERP_KERNEL::NORM_SEG2);
4487               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
4488               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
4489               newConnIPtr[1]=newConnIPtr[0]+3;
4490             }
4491         }
4492       else
4493         {
4494           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4495           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
4496           newConnIPtr[1]=newConnIPtr[0]+3;
4497         }
4498     }
4499   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tasselation : no update needed
4500     return ;
4501   _types=types;
4502   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
4503   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnArr=DataArrayInt::New();
4504   newConnArr->alloc((int)newConn.size(),1);
4505   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
4506   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
4507   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=DataArrayDouble::New();
4508   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
4509   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
4510   std::copy(addCoo.begin(),addCoo.end(),work);
4511   DataArrayDouble::SetArrayIn(newCoords,_coords);
4512   updateTime();
4513 }
4514
4515 /*!
4516  * This methods modify this by converting each cells into simplex cell, that is too say triangle for meshdim==2 or tetra for meshdim==3.
4517  * This cut into simplex is performed following the parameter \a policy. This method so typically increases the number of cells of \a this.
4518  * This method \b keeps the number of nodes \b unchanged. That's why the splitting policy in 3D INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4519  * This method returns new2old newly allocated array that specifies a each cell of \a this after the call what was its id it comes.
4520  * 
4521  * The semantic of \a policy parameter :
4522  * - 1 only QUAD4. For QUAD4 the cut is done along 0-2 diagonal for QUAD4
4523  * - 2 only QUAD4. For QUAD4 the cut is done along 1-3 diagonal for QUAD4
4524  * - PLANAR_FACE_5 only HEXA8. All HEXA8 are split into 5 TETRA4
4525  * - PLANAR_FACE_6 only HEXA8. All HEXA8 are split into 6 TETRA4
4526  */
4527 DataArrayInt *MEDCouplingUMesh::simplexize(int policy) throw(INTERP_KERNEL::Exception)
4528 {
4529   switch(policy)
4530     {
4531     case 0:
4532       return simplexizePol0();
4533     case 1:
4534       return simplexizePol1();
4535     case (int) INTERP_KERNEL::PLANAR_FACE_5:
4536       return simplexizePlanarFace5();
4537     case (int) INTERP_KERNEL::PLANAR_FACE_6:
4538       return simplexizePlanarFace6();
4539     default:
4540       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexize : unrecognized policy ! Must be :\n  - 0 or 1 (only available for meshdim=2) \n  - PLANAR_FACE_5, PLANAR_FACE_6  (only for meshdim=3)");
4541     }
4542 }
4543
4544 bool MEDCouplingUMesh::areOnlySimplexCells() const throw(INTERP_KERNEL::Exception)
4545 {
4546   checkFullyDefined();
4547   if(getMeshDimension()<1)
4548     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim >= 1 !");
4549   int nbCells=getNumberOfCells();
4550   const int *conn=_nodal_connec->getConstPointer();
4551   const int *connI=_nodal_connec_index->getConstPointer();
4552   for(int i=0;i<nbCells;i++)
4553     {
4554       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4555       if(!cm.isSimplex())
4556         return false;
4557     }
4558   return true;
4559 }
4560
4561 /*!
4562  * This method implements policy 0 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4563  */
4564 DataArrayInt *MEDCouplingUMesh::simplexizePol0() throw(INTERP_KERNEL::Exception)
4565 {
4566   checkConnectivityFullyDefined();
4567   if(getMeshDimension()!=2)
4568     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
4569   int nbOfCells=getNumberOfCells();
4570   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
4571   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
4572   ret->alloc(nbOfCells+nbOfCutCells,1);
4573   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
4574   int *retPt=ret->getPointer();
4575   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4576   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4577   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
4578   newConn->alloc(getMeshLength()+3*nbOfCutCells,1);
4579   int *pt=newConn->getPointer();
4580   int *ptI=newConnI->getPointer();
4581   ptI[0]=0;
4582   const int *oldc=_nodal_connec->getConstPointer();
4583   const int *ci=_nodal_connec_index->getConstPointer();
4584   for(int i=0;i<nbOfCells;i++,ci++)
4585     {
4586       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
4587         {
4588           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
4589                             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
4590           pt=std::copy(tmp,tmp+8,pt);
4591           ptI[1]=ptI[0]+4;
4592           ptI[2]=ptI[0]+8;
4593           *retPt++=i;
4594           *retPt++=i;
4595           ptI+=2;
4596         }
4597       else
4598         {
4599           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4600           ptI[1]=ptI[0]+ci[1]-ci[0];
4601           ptI++;
4602           *retPt++=i;
4603         }
4604     }
4605   _nodal_connec->decrRef();
4606   _nodal_connec=newConn.retn();
4607   _nodal_connec_index->decrRef();
4608   _nodal_connec_index=newConnI.retn();
4609   computeTypes();
4610   updateTime();
4611   return ret.retn();
4612 }
4613
4614 /*!
4615  * This method implements policy 1 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4616  */
4617 DataArrayInt *MEDCouplingUMesh::simplexizePol1() throw(INTERP_KERNEL::Exception)
4618 {
4619   checkConnectivityFullyDefined();
4620   if(getMeshDimension()!=2)
4621     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
4622   int nbOfCells=getNumberOfCells();
4623   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
4624   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
4625   ret->alloc(nbOfCells+nbOfCutCells,1);
4626   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
4627   int *retPt=ret->getPointer();
4628   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4629   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4630   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
4631   newConn->alloc(getMeshLength()+3*nbOfCutCells,1);
4632   int *pt=newConn->getPointer();
4633   int *ptI=newConnI->getPointer();
4634   ptI[0]=0;
4635   const int *oldc=_nodal_connec->getConstPointer();
4636   const int *ci=_nodal_connec_index->getConstPointer();
4637   for(int i=0;i<nbOfCells;i++,ci++)
4638     {
4639       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
4640         {
4641           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
4642                             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
4643           pt=std::copy(tmp,tmp+8,pt);
4644           ptI[1]=ptI[0]+4;
4645           ptI[2]=ptI[0]+8;
4646           *retPt++=i;
4647           *retPt++=i;
4648           ptI+=2;
4649         }
4650       else
4651         {
4652           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4653           ptI[1]=ptI[0]+ci[1]-ci[0];
4654           ptI++;
4655           *retPt++=i;
4656         }
4657     }
4658   _nodal_connec->decrRef();
4659   _nodal_connec=newConn.retn();
4660   _nodal_connec_index->decrRef();
4661   _nodal_connec_index=newConnI.retn();
4662   computeTypes();
4663   updateTime();
4664   return ret.retn();
4665 }
4666
4667 /*!
4668  * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4669  */
4670 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5() throw(INTERP_KERNEL::Exception)
4671 {
4672   checkConnectivityFullyDefined();
4673   if(getMeshDimension()!=3)
4674     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
4675   int nbOfCells=getNumberOfCells();
4676   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
4677   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
4678   ret->alloc(nbOfCells+4*nbOfCutCells,1);
4679   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
4680   int *retPt=ret->getPointer();
4681   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4682   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4683   newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
4684   newConn->alloc(getMeshLength()+16*nbOfCutCells,1);//21
4685   int *pt=newConn->getPointer();
4686   int *ptI=newConnI->getPointer();
4687   ptI[0]=0;
4688   const int *oldc=_nodal_connec->getConstPointer();
4689   const int *ci=_nodal_connec_index->getConstPointer();
4690   for(int i=0;i<nbOfCells;i++,ci++)
4691     {
4692       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
4693         {
4694           for(int j=0;j<5;j++,pt+=5,ptI++)
4695             {
4696               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
4697               pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+3]+1];
4698               *retPt++=i;
4699               ptI[1]=ptI[0]+5;
4700             }
4701         }
4702       else
4703         {
4704           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4705           ptI[1]=ptI[0]+ci[1]-ci[0];
4706           ptI++;
4707           *retPt++=i;
4708         }
4709     }
4710   _nodal_connec->decrRef();
4711   _nodal_connec=newConn.retn();
4712   _nodal_connec_index->decrRef();
4713   _nodal_connec_index=newConnI.retn();
4714   computeTypes();
4715   updateTime();
4716   return ret.retn();
4717 }
4718
4719 /*!
4720  * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4721  */
4722 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6() throw(INTERP_KERNEL::Exception)
4723 {
4724   checkConnectivityFullyDefined();
4725   if(getMeshDimension()!=3)
4726     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
4727   int nbOfCells=getNumberOfCells();
4728   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
4729   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
4730   ret->alloc(nbOfCells+5*nbOfCutCells,1);
4731   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
4732   int *retPt=ret->getPointer();
4733   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4734   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4735   newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
4736   newConn->alloc(getMeshLength()+21*nbOfCutCells,1);
4737   int *pt=newConn->getPointer();
4738   int *ptI=newConnI->getPointer();
4739   ptI[0]=0;
4740   const int *oldc=_nodal_connec->getConstPointer();
4741   const int *ci=_nodal_connec_index->getConstPointer();
4742   for(int i=0;i<nbOfCells;i++,ci++)
4743     {
4744       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
4745         {
4746           for(int j=0;j<6;j++,pt+=5,ptI++)
4747             {
4748               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
4749               pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+3]+1];
4750               *retPt++=i;
4751               ptI[1]=ptI[0]+5;
4752             }
4753         }
4754       else
4755         {
4756           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4757           ptI[1]=ptI[0]+ci[1]-ci[0];
4758           ptI++;
4759           *retPt++=i;
4760         }
4761     }
4762   _nodal_connec->decrRef();
4763   _nodal_connec=newConn.retn();
4764   _nodal_connec_index->decrRef();
4765   _nodal_connec_index=newConnI.retn();
4766   computeTypes();
4767   updateTime();
4768   return ret.retn();
4769 }
4770
4771 /*!
4772  * This private method is used to subdivide edges of a mesh with meshdim==2. If 'this' has no a meshdim equal to 2 an exception will be thrown.
4773  * This method completly ignore coordinates.
4774  * @param nodeSubdived is the nodal connectivity of subdivision of edges
4775  * @param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
4776  * @param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
4777  * @param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
4778  */
4779 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex) throw(INTERP_KERNEL::Exception)
4780 {
4781   checkFullyDefined();
4782   if(getMeshDimension()!=2)
4783     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
4784   int nbOfCells=getNumberOfCells();
4785   int *connI=_nodal_connec_index->getPointer();
4786   int newConnLgth=0;
4787   for(int i=0;i<nbOfCells;i++,connI++)
4788     {
4789       int offset=descIndex[i];
4790       int nbOfEdges=descIndex[i+1]-offset;
4791       //
4792       bool ddirect=desc[offset+nbOfEdges-1]>0;
4793       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
4794       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
4795       for(int j=0;j<nbOfEdges;j++)
4796         {
4797           bool direct=desc[offset+j]>0;
4798           int edgeId=std::abs(desc[offset+j])-1;
4799           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
4800             {
4801               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
4802               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
4803               int ref2=direct?id1:id2;
4804               if(ref==ref2)
4805                 {
4806                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
4807                   newConnLgth+=nbOfSubNodes-1;
4808                   ref=direct?id2:id1;
4809                 }
4810               else
4811                 {
4812                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
4813                   throw INTERP_KERNEL::Exception(oss.str().c_str());
4814                 }
4815             }
4816           else
4817             {
4818               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
4819             }
4820         }
4821       newConnLgth++;//+1 is for cell type
4822       connI[1]=newConnLgth;
4823     }
4824   //
4825   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4826   newConn->alloc(newConnLgth,1);
4827   int *work=newConn->getPointer();
4828   for(int i=0;i<nbOfCells;i++)
4829     {
4830       *work++=INTERP_KERNEL::NORM_POLYGON;
4831       int offset=descIndex[i];
4832       int nbOfEdges=descIndex[i+1]-offset;
4833       for(int j=0;j<nbOfEdges;j++)
4834         {
4835           bool direct=desc[offset+j]>0;
4836           int edgeId=std::abs(desc[offset+j])-1;
4837           if(direct)
4838             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
4839           else
4840             {
4841               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
4842               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
4843               work=std::copy(it,it+nbOfSubNodes-1,work);
4844             }
4845         }
4846     }
4847   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
4848   _types.clear();
4849   if(nbOfCells>0)
4850     _types.insert(INTERP_KERNEL::NORM_POLYGON);
4851 }
4852
4853 /*!
4854  * This method converts all degenerated cells to simpler cells. For example a NORM_QUAD4 cell consituted from 2 same node id in its
4855  * nodal connectivity will be transform to a NORM_TRI3 cell.
4856  * This method works \b only \b on \b linear cells.
4857  * This method works on nodes ids, that is to say a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes
4858  * method could be usefull before calling this method in case of presence of several pair of nodes located on same position.
4859  * This method throws an exception if 'this' is not fully defined (connectivity).
4860  * This method throws an exception too if a "too" degenerated cell is detected. For example a NORM_TRI3 with 3 times the same node id.
4861  */
4862 void MEDCouplingUMesh::convertDegeneratedCells() throw(INTERP_KERNEL::Exception)
4863 {
4864   checkFullyDefined();
4865   if(getMeshDimension()<=1)
4866     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4867   int nbOfCells=getNumberOfCells();
4868   if(nbOfCells<1)
4869     return ;
4870   int initMeshLgth=getMeshLength();
4871   int *conn=_nodal_connec->getPointer();
4872   int *index=_nodal_connec_index->getPointer();
4873   int posOfCurCell=0;
4874   int newPos=0;
4875   int lgthOfCurCell;
4876   for(int i=0;i<nbOfCells;i++)
4877     {
4878       lgthOfCurCell=index[i+1]-posOfCurCell;
4879       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4880       int newLgth;
4881       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4882                                                                                                      conn+newPos+1,newLgth);
4883       conn[newPos]=newType;
4884       newPos+=newLgth+1;
4885       posOfCurCell=index[i+1];
4886       index[i+1]=newPos;
4887     }
4888   if(newPos!=initMeshLgth)
4889     _nodal_connec->reAlloc(newPos);
4890   computeTypes();
4891 }
4892
4893 /*!
4894  * This method checks that all or only polygons (depending 'polyOnly' parameter) 2D cells are correctly oriented relative to 'vec' vector.
4895  * The 'vec' vector has to have a non nul norm.
4896  * If not 'cells' parameter will be appended with cellIds of incorrect cells.
4897  * @throw when 'this' is not a mesh with meshdim==2 and spacedim==3
4898  */
4899 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const throw(INTERP_KERNEL::Exception)
4900 {
4901   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4902     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4903   int nbOfCells=getNumberOfCells();
4904   const int *conn=_nodal_connec->getConstPointer();
4905   const int *connI=_nodal_connec_index->getConstPointer();
4906   const double *coordsPtr=_coords->getConstPointer();
4907   for(int i=0;i<nbOfCells;i++)
4908     {
4909       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4910       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4911         {
4912           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4913           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4914             cells.push_back(i);
4915         }
4916     }
4917 }
4918
4919 /*!
4920  * This method orient correctly (if needed) all or only polygons (depending 'polyOnly' parameter)  2D cells are correctly oriented relative to 'vec' vector.
4921  * The 'vec' vector has to have a non nul norm.
4922  * @throw when 'this' is not a mesh with meshdim==2 and spacedim==3
4923  */
4924 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly) throw(INTERP_KERNEL::Exception)
4925 {
4926   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4927     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4928   int nbOfCells=getNumberOfCells();
4929   int *conn=_nodal_connec->getPointer();
4930   const int *connI=_nodal_connec_index->getConstPointer();
4931   const double *coordsPtr=_coords->getConstPointer();
4932   bool isModified=false;
4933   for(int i=0;i<nbOfCells;i++)
4934     {
4935       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4936       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4937         {
4938           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4939           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4940             {
4941               isModified=true;
4942               std::vector<int> tmp(connI[i+1]-connI[i]-2);
4943               std::copy(conn+connI[i]+2,conn+connI[i+1],tmp.rbegin());
4944               std::copy(tmp.begin(),tmp.end(),conn+connI[i]+2);
4945             }
4946         }
4947     }
4948   if(isModified)
4949     _nodal_connec->declareAsNew();
4950   updateTime();
4951 }
4952
4953 /*!
4954  * This method checks that all polyhedrons cells have correctly oriented faces.
4955  * If not, 'cells' parameter will be appended with cellIds of incorrect cells.
4956  * @throw when 'this' is not a mesh with meshdim==3 and spacedim==3
4957  */
4958 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const throw(INTERP_KERNEL::Exception)
4959 {
4960   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4961     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4962   int nbOfCells=getNumberOfCells();
4963   const int *conn=_nodal_connec->getConstPointer();
4964   const int *connI=_nodal_connec_index->getConstPointer();
4965   const double *coordsPtr=_coords->getConstPointer();
4966   for(int i=0;i<nbOfCells;i++)
4967     {
4968       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4969       if(type==INTERP_KERNEL::NORM_POLYHED)
4970         {
4971           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4972             cells.push_back(i);
4973         }
4974     }
4975 }
4976
4977 /*!
4978  * This method tries to orient correctly polhedrons cells.
4979  * 
4980  * \throw when 'this' is not a mesh with meshdim==3 and spacedim==3. An exception is also thrown when the attempt of reparation fails.
4981  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4982  */
4983 void MEDCouplingUMesh::orientCorrectlyPolyhedrons() throw(INTERP_KERNEL::Exception)
4984 {
4985   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4986     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4987   int nbOfCells=getNumberOfCells();
4988   int *conn=_nodal_connec->getPointer();
4989   const int *connI=_nodal_connec_index->getConstPointer();
4990   const double *coordsPtr=_coords->getConstPointer();
4991   for(int i=0;i<nbOfCells;i++)
4992     {
4993       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4994       if(type==INTERP_KERNEL::NORM_POLYHED)
4995         {
4996           try
4997             {
4998               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4999                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5000             }
5001           catch(INTERP_KERNEL::Exception& e)
5002             {
5003               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5004               throw INTERP_KERNEL::Exception(oss.str().c_str());
5005             }
5006         }
5007     }
5008   updateTime();
5009 }
5010
5011 /*!
5012  * This method is expected to be applied on a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
5013  * This method analyzes only linear extruded 3D cells (NORM_HEXA8,NORM_PENTA6,NORM_HEXGP12...)
5014  * If some extruded cells does not fulfill the MED norm for extruded cells (first face of 3D cell should be oriented to the exterior of the 3D cell).
5015  * Some viewers are very careful of that (SMESH), but ParaVis ignore that.
5016  *
5017  * \ret a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5018  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5019  */
5020 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells() throw(INTERP_KERNEL::Exception)
5021 {
5022   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5023   if(getMeshDimension()!=3)
5024     throw INTERP_KERNEL::Exception(msg);
5025   int spaceDim=getSpaceDimension();
5026   if(spaceDim!=3)
5027     throw INTERP_KERNEL::Exception(msg);
5028   //
5029   int nbOfCells=getNumberOfCells();
5030   int *conn=_nodal_connec->getPointer();
5031   const int *connI=_nodal_connec_index->getConstPointer();
5032   const double *coo=getCoords()->getConstPointer();
5033   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
5034   for(int i=0;i<nbOfCells;i++)
5035     {
5036       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5037       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5038         {
5039           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5040             {
5041               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5042               cells->pushBackSilent(i);
5043             }
5044         }
5045     }
5046   return cells.retn();
5047 }
5048
5049 /*!
5050  * This method is a faster method to correct orientation of all 3D cells in \a this.
5051  * This method works only if \a this is a 3D mesh, that is to say a mesh with mesh dimension 3 and a space dimension 3.
5052  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkCoherency2 should throw no exception.
5053  * 
5054  * \ret a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5055  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, 
5056  */
5057 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells() throw(INTERP_KERNEL::Exception)
5058 {
5059   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5060     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5061   int nbOfCells=getNumberOfCells();
5062   int *conn=_nodal_connec->getPointer();
5063   const int *connI=_nodal_connec_index->getConstPointer();
5064   const double *coordsPtr=_coords->getConstPointer();
5065   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5066   for(int i=0;i<nbOfCells;i++)
5067     {
5068       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5069       switch(type)
5070         {
5071         case INTERP_KERNEL::NORM_TETRA4:
5072           {
5073             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5074               {
5075                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5076                 ret->pushBackSilent(i);
5077               }
5078             break;
5079           }
5080         case INTERP_KERNEL::NORM_PYRA5:
5081           {
5082             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5083               {
5084                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5085                 ret->pushBackSilent(i);
5086               }
5087             break;
5088           }
5089         case INTERP_KERNEL::NORM_PENTA6:
5090         case INTERP_KERNEL::NORM_HEXA8:
5091         case INTERP_KERNEL::NORM_HEXGP12:
5092           {
5093             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5094               {
5095                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5096                 ret->pushBackSilent(i);
5097               }
5098             break;
5099           }
5100         case INTERP_KERNEL::NORM_POLYHED:
5101           {
5102             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5103               {
5104                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5105                 ret->pushBackSilent(i);
5106               }
5107             break;
5108           }
5109         default:
5110           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orientCorrectly3DCells : Your mesh contains type of cell not supported yet ! send mail to anthony.geay@cea.fr to add it !");
5111         }
5112     }
5113   updateTime();
5114   return ret.retn();
5115 }
5116
5117 /*!
5118  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5119  * If it is not the case an exception will be thrown.
5120  * This method is fast because the first cell of 'this' is used to compute the plane.
5121  * @param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5122  * @param pos output of size at least 3 used to store a point owned of searched plane.
5123  */
5124 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const throw(INTERP_KERNEL::Exception)
5125 {
5126   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5127     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5128   const int *conn=_nodal_connec->getConstPointer();
5129   const int *connI=_nodal_connec_index->getConstPointer();
5130   const double *coordsPtr=_coords->getConstPointer();
5131   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5132   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5133 }
5134
5135 /*!
5136  * The returned newly created field has to be managed by the caller.
5137  * This method returns a field on cell with no time lying on 'this'. The meshdimension and spacedimension of this are expected to be both in [2,3]. If not an exception will be thrown.
5138  * This method for the moment only deals with NORM_TRI3, NORM_QUAD4 and NORM_TETRA4 geometric types.
5139  * If a cell has an another type an exception will be thrown.
5140  */
5141 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const throw(INTERP_KERNEL::Exception)
5142 {
5143   checkCoherency();
5144   int spaceDim=getSpaceDimension();
5145   int meshDim=getMeshDimension();
5146   if(spaceDim!=2 && spaceDim!=3)
5147     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5148   if(meshDim!=2 && meshDim!=3)
5149     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5150   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5151   ret->setMesh(this);
5152   int nbOfCells=getNumberOfCells();
5153   DataArrayDouble *arr=DataArrayDouble::New();
5154   arr->alloc(nbOfCells,1);
5155   double *pt=arr->getPointer();
5156   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5157   arr->decrRef();
5158   const int *conn=_nodal_connec->getConstPointer();
5159   const int *connI=_nodal_connec_index->getConstPointer();
5160   const double *coo=_coords->getConstPointer();
5161   double tmp[12];
5162   for(int i=0;i<nbOfCells;i++,pt++)
5163     {
5164       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5165       switch(t)
5166         {
5167           case INTERP_KERNEL::NORM_TRI3:
5168             {
5169               FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5170               *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5171               break;
5172             }
5173           case INTERP_KERNEL::NORM_QUAD4:
5174             {
5175               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5176               *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5177               break;
5178             }
5179           case INTERP_KERNEL::NORM_TETRA4:
5180             {
5181               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5182               *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5183               break;
5184             }
5185         default:
5186           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5187         }
5188       conn+=connI[i+1]-connI[i];
5189     }
5190   ret->setName("EdgeRatio");
5191   ret->synchronizeTimeWithSupport();
5192   return ret.retn();
5193 }
5194
5195 /*!
5196  * The returned newly created field has to be managed by the caller.
5197  * This method returns a field on cell with no time lying on 'this'. The meshdimension and spacedimension of this are expected to be both in [2,3]. If not an exception will be thrown.
5198  * This method for the moment only deals with NORM_TRI3, NORM_QUAD4 and NORM_TETRA4 geometric types.
5199  * If a cell has an another type an exception will be thrown.
5200  */
5201 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const throw(INTERP_KERNEL::Exception)
5202 {
5203   checkCoherency();
5204   int spaceDim=getSpaceDimension();
5205   int meshDim=getMeshDimension();
5206   if(spaceDim!=2 && spaceDim!=3)
5207     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5208   if(meshDim!=2 && meshDim!=3)
5209     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5210   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5211   ret->setMesh(this);
5212   int nbOfCells=getNumberOfCells();
5213   DataArrayDouble *arr=DataArrayDouble::New();
5214   arr->alloc(nbOfCells,1);
5215   double *pt=arr->getPointer();
5216   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5217   arr->decrRef();
5218   const int *conn=_nodal_connec->getConstPointer();
5219   const int *connI=_nodal_connec_index->getConstPointer();
5220   const double *coo=_coords->getConstPointer();
5221   double tmp[12];
5222   for(int i=0;i<nbOfCells;i++,pt++)
5223     {
5224       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5225       switch(t)
5226         {
5227           case INTERP_KERNEL::NORM_TRI3:
5228             {
5229               FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5230               *pt=INTERP_KERNEL::triAspectRatio(tmp);
5231               break;
5232             }
5233           case INTERP_KERNEL::NORM_QUAD4:
5234             {
5235               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5236               *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5237               break;
5238             }
5239           case INTERP_KERNEL::NORM_TETRA4:
5240             {
5241               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5242               *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5243               break;
5244             }
5245         default:
5246           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5247         }
5248       conn+=connI[i+1]-connI[i];
5249     }
5250   ret->setName("AspectRatio");
5251   ret->synchronizeTimeWithSupport();
5252   return ret.retn();
5253 }
5254
5255 /*!
5256  * The returned newly created field has to be managed by the caller.
5257  * This method returns a field on cell with no time lying on 'this'. The meshdimension must be equal to 2 and the spacedimension must be equal to 3. If not an exception will be thrown.
5258  * This method for the moment only deals with NORM_QUAD4 geometric type.
5259  * If a cell has an another type an exception will be thrown.
5260  */
5261 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const throw(INTERP_KERNEL::Exception)
5262 {
5263   checkCoherency();
5264   int spaceDim=getSpaceDimension();
5265   int meshDim=getMeshDimension();
5266   if(spaceDim!=3)
5267     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5268   if(meshDim!=2)
5269     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5270   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5271   ret->setMesh(this);
5272   int nbOfCells=getNumberOfCells();
5273   DataArrayDouble *arr=DataArrayDouble::New();
5274   arr->alloc(nbOfCells,1);
5275   double *pt=arr->getPointer();
5276   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5277   arr->decrRef();
5278   const int *conn=_nodal_connec->getConstPointer();
5279   const int *connI=_nodal_connec_index->getConstPointer();
5280   const double *coo=_coords->getConstPointer();
5281   double tmp[12];
5282   for(int i=0;i<nbOfCells;i++,pt++)
5283     {
5284       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5285       switch(t)
5286         {
5287           case INTERP_KERNEL::NORM_QUAD4:
5288             {
5289               FillInCompact3DMode(3,4,conn+1,coo,tmp);
5290               *pt=INTERP_KERNEL::quadWarp(tmp);
5291               break;
5292             }
5293         default:
5294           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5295         }
5296       conn+=connI[i+1]-connI[i];
5297     }
5298   ret->setName("Warp");
5299   ret->synchronizeTimeWithSupport();
5300   return ret.retn();
5301 }
5302
5303 /*!
5304  * The returned newly created field has to be managed by the caller.
5305  * This method returns a field on cell with no time lying on 'this'. The meshdimension must be equal to 2 and the spacedimension must be equal to 3. If not an exception will be thrown.
5306  * This method for the moment only deals with NORM_QUAD4 geometric type.
5307  * If a cell has an another type an exception will be thrown.
5308  */
5309 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const throw(INTERP_KERNEL::Exception)
5310 {
5311   checkCoherency();
5312   int spaceDim=getSpaceDimension();
5313   int meshDim=getMeshDimension();
5314   if(spaceDim!=3)
5315     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5316   if(meshDim!=2)
5317     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5318   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5319   ret->setMesh(this);
5320   int nbOfCells=getNumberOfCells();
5321   DataArrayDouble *arr=DataArrayDouble::New();
5322   arr->alloc(nbOfCells,1);
5323   double *pt=arr->getPointer();
5324   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5325   arr->decrRef();
5326   const int *conn=_nodal_connec->getConstPointer();
5327   const int *connI=_nodal_connec_index->getConstPointer();
5328   const double *coo=_coords->getConstPointer();
5329   double tmp[12];
5330   for(int i=0;i<nbOfCells;i++,pt++)
5331     {
5332       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5333       switch(t)
5334         {
5335           case INTERP_KERNEL::NORM_QUAD4:
5336             {
5337               FillInCompact3DMode(3,4,conn+1,coo,tmp);
5338               *pt=INTERP_KERNEL::quadSkew(tmp);
5339               break;
5340             }
5341         default:
5342           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5343         }
5344       conn+=connI[i+1]-connI[i];
5345     }
5346   ret->setName("Skew");
5347   ret->synchronizeTimeWithSupport();
5348   return ret.retn();
5349 }
5350
5351 /*!
5352  * This method aggregate the bbox of each cell and put it into bbox parameter.
5353  * @param bbox out parameter of size 2*spacedim*nbOfcells.
5354  */
5355 void MEDCouplingUMesh::getBoundingBoxForBBTree(std::vector<double>& bbox) const
5356 {
5357   int spaceDim=getSpaceDimension();
5358   int nbOfCells=getNumberOfCells();
5359   bbox.resize(2*nbOfCells*spaceDim);
5360   for(int i=0;i<nbOfCells*spaceDim;i++)
5361     {
5362       bbox[2*i]=std::numeric_limits<double>::max();
5363       bbox[2*i+1]=-std::numeric_limits<double>::max();
5364     }
5365   const double *coordsPtr=_coords->getConstPointer();
5366   const int *conn=_nodal_connec->getConstPointer();
5367   const int *connI=_nodal_connec_index->getConstPointer();
5368   for(int i=0;i<nbOfCells;i++)
5369     {
5370       int offset=connI[i]+1;
5371       int nbOfNodesForCell=connI[i+1]-offset;
5372       for(int j=0;j<nbOfNodesForCell;j++)
5373         {
5374           int nodeId=conn[offset+j];
5375           if(nodeId>=0)
5376             for(int k=0;k<spaceDim;k++)
5377               {
5378                 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5379                 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5380               }
5381         }
5382     }
5383 }
5384
5385 /// @cond INTERNAL
5386
5387 namespace ParaMEDMEMImpl
5388 {
5389   class ConnReader
5390   {
5391   public:
5392     ConnReader(const int *c, int val):_conn(c),_val(val) { }
5393     bool operator() (const int& pos) { return _conn[pos]!=_val; }
5394   private:
5395     const int *_conn;
5396     int _val;
5397   };
5398
5399   class ConnReader2
5400   {
5401   public:
5402     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5403     bool operator() (const int& pos) { return _conn[pos]==_val; }
5404   private:
5405     const int *_conn;
5406     int _val;
5407   };
5408 }
5409
5410 /// @endcond
5411
5412 /*!
5413  * This method expects that 'this' is sorted by types. If not an exception will be thrown.
5414  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5415  * 'this' is composed in cell types.
5416  * The returned array is of size 3*n where n is the number of different types present in 'this'. 
5417  * For every k in [0,n] ret[3*k+2]==0 because it has no sense here. 
5418  * This parameter is kept only for compatibility with other methode listed above.
5419  */
5420 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const throw(INTERP_KERNEL::Exception)
5421 {
5422   checkConnectivityFullyDefined();
5423   const int *conn=_nodal_connec->getConstPointer();
5424   const int *connI=_nodal_connec_index->getConstPointer();
5425   const int *work=connI;
5426   int nbOfCells=getNumberOfCells();
5427   std::size_t n=getAllTypes().size();
5428   std::vector<int> ret(3*n,0); //ret[3*k+2]==0 because it has no sense here
5429   std::set<INTERP_KERNEL::NormalizedCellType> types;
5430   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5431     {
5432       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5433       if(types.find(typ)!=types.end())
5434         {
5435           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5436           oss << " is not contiguous !";
5437           throw INTERP_KERNEL::Exception(oss.str().c_str());
5438         }
5439       types.insert(typ);
5440       ret[3*i]=typ;
5441       const int *work2=std::find_if(work+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,typ));
5442       ret[3*i+1]=(int)std::distance(work,work2);
5443       work=work2;
5444     }
5445   return ret;
5446 }
5447
5448 /*!
5449  * This method is used to check that this has contiguous cell type in same order than described in 'code'.
5450  * only for types cell, type node is not managed.
5451  * Format of 'code' is the following. 'code' should be of size 3*n and non empty. If not an exception is thrown.
5452  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5453  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5454  * If 2 or more same geometric type is in 'code' and exception is thrown too.
5455  *
5456  * This method firstly checks
5457  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5458  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5459  * an exception is thrown too.
5460  * 
5461  * If all geometric types in 'code' are exactly those in 'this' null pointer is returned.
5462  * If it exists a geometric type in 'this' \b not in 'code' \b no exception is thrown 
5463  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5464  */
5465 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const throw(INTERP_KERNEL::Exception)
5466 {
5467   if(code.empty())
5468     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5469   std::size_t sz=code.size();
5470   std::size_t n=sz/3;
5471   if(sz%3!=0)
5472     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5473   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5474   int nb=0;
5475   for(std::size_t i=0;i<n;i++)
5476     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5477       {
5478         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5479         nb+=code[3*i+1];
5480         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5481           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5482       }
5483   if(types.size()!=n)
5484     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5485   if(idsPerType.empty())
5486     {
5487       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5488         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5489       if(types.size()==_types.size())
5490         return 0;
5491     }
5492   DataArrayInt *ret=DataArrayInt::New();
5493   ret->alloc(nb,1);
5494   int *retPtr=ret->getPointer();
5495   const int *connI=_nodal_connec_index->getConstPointer();
5496   const int *conn=_nodal_connec->getConstPointer();
5497   int nbOfCells=getNumberOfCells();
5498   const int *i=connI;
5499   int kk=0;
5500   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5501     {
5502       i=std::find_if(i,connI+nbOfCells,ParaMEDMEMImpl::ConnReader2(conn,(int)(*it)));
5503       int offset=(int)std::distance(connI,i);
5504       if(code[3*kk+2]==-1)
5505         {
5506           const int *j=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)(*it)));
5507           std::size_t pos2=std::distance(i,j);
5508           for(std::size_t k=0;k<pos2;k++)
5509             *retPtr++=(int)k+offset;
5510           i=j;
5511         }
5512       else
5513         {
5514           retPtr=std::transform(idsPerType[code[3*kk+2]]->getConstPointer(),idsPerType[code[3*kk+2]]->getConstPointer()+idsPerType[code[3*kk+2]]->getNbOfElems(),
5515                                 retPtr,std::bind2nd(std::plus<int>(),offset));
5516         }
5517     }
5518   return ret;
5519 }
5520
5521 /*!
5522  * This method makes the hypothesis that \at this is sorted by type. If not an exception will be thrown.
5523  * This method is the opposite of MEDCouplingUMesh::checkTypeConsistencyAndContig method. Given a list of cells in \a profile it returns a list of sub-profiles sorted by geo type.
5524  * The result is put in the array \a idsPerType. In the returned parameter \a code, foreach i \a code[3*i+2] refers (if different from -1) to a location into the \a idsPerType.
5525  * This method has 1 input \a profile and 3 outputs \a code' \a idsInPflPerType and \a idsPerType.
5526  * 
5527  * @param [out] code is a vector of size 3*n where n is the number of different geometric type in \a this \b reduced to the profile \a profile. \a code has exactly the same semantic than in MEDCouplingUMesh::checkTypeConsistencyAndContig method.
5528  * @param [out] idsInPflPerType is a vector of size of different geometric type in the subpart defined by \a profile of \a this ( equal to \a code.size()/3). For each i,
5529  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5530  * @param [out] idsPerType is a vector of size of different sub profiles needed to be defined to represent the profile \a profile for a given geometric type.
5531  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5532  * @throw if \a profile has not exactly one component. It throws too, if \a profile contains some values not in [0,getNumberOfCells()) or if 'this' is not fully defined
5533  */
5534 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const throw(INTERP_KERNEL::Exception)
5535 {
5536   if(profile->getNumberOfComponents()!=1)
5537     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5538   checkConnectivityFullyDefined();
5539   const int *conn=_nodal_connec->getConstPointer();
5540   const int *connI=_nodal_connec_index->getConstPointer();
5541   int nbOfCells=getNumberOfCells();
5542   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5543   std::vector<int> typeRangeVals(1);
5544   for(const int *i=connI;i!=connI+nbOfCells;)
5545     {
5546       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5547       if(std::find(types.begin(),types.end(),curType)!=types.end())
5548         {
5549           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5550         }
5551       types.push_back(curType);
5552       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5553       typeRangeVals.push_back((int)std::distance(connI,i));
5554     }
5555   //
5556   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5557   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5558   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp0=castArr;
5559   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1=rankInsideCast;
5560   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp2=castsPresent;
5561   //
5562   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5563   code.resize(3*nbOfCastsFinal);
5564   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsInPflPerType2;
5565   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsPerType2;
5566   for(int i=0;i<nbOfCastsFinal;i++)
5567     {
5568       int castId=castsPresent->getIJ(i,0);
5569       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp3=castArr->getIdsEqual(castId);
5570       idsInPflPerType2.push_back(tmp3);
5571       code[3*i]=(int)types[castId];
5572       code[3*i+1]=tmp3->getNumberOfTuples();
5573       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
5574       if(tmp4->getNumberOfTuples()!=typeRangeVals[castId+1]-typeRangeVals[castId] || !tmp4->isIdentity())
5575         {
5576           tmp4->copyStringInfoFrom(*profile);
5577           idsPerType2.push_back(tmp4);
5578           code[3*i+2]=(int)idsPerType2.size()-1;
5579         }
5580       else
5581         {
5582           code[3*i+2]=-1;
5583         }
5584     }
5585   std::size_t sz2=idsInPflPerType2.size();
5586   idsInPflPerType.resize(sz2);
5587   for(std::size_t i=0;i<sz2;i++)
5588     {
5589       DataArrayInt *locDa=idsInPflPerType2[i];
5590       locDa->incrRef();
5591       idsInPflPerType[i]=locDa;
5592     }
5593   std::size_t sz=idsPerType2.size();
5594   idsPerType.resize(sz);
5595   for(std::size_t i=0;i<sz;i++)
5596     {
5597       DataArrayInt *locDa=idsPerType2[i];
5598       locDa->incrRef();
5599       idsPerType[i]=locDa;
5600     }
5601 }
5602
5603 /*!
5604  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5605  * This method make the assumption that 'this' and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5606  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5607  * This method returns 5+2 elements. 'desc', 'descIndx', 'revDesc', 'revDescIndx' and 'meshnM1' behaves exactly as ParaMEDMEM::MEDCouplingUMesh::buildDescendingConnectivity except the content as described after. The returned array specifies the n-1 mesh reordered by type as MEDMEM does. 'nM1LevMeshIds' contains the ids in returned 'meshnM1'. Finally 'meshnM1Old2New' contains numbering old2new that is to say the cell #k in coarse 'nM1LevMesh' will have the number ret[k] in returned mesh 'nM1LevMesh' MEDMEM reordered.
5608  */
5609 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const throw(INTERP_KERNEL::Exception)
5610 {
5611   checkFullyDefined();
5612   nM1LevMesh->checkFullyDefined();
5613   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5614     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5615   if(_coords!=nM1LevMesh->getCoords())
5616     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5617   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp0=DataArrayInt::New();
5618   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1=DataArrayInt::New();
5619   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5620   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5621   desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
5622   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5623   tmp->setConnectivity(tmp0,tmp1);
5624   tmp->renumberCells(ret0->getConstPointer(),false);
5625   revDesc=tmp->getNodalConnectivity();
5626   revDescIndx=tmp->getNodalConnectivityIndex();
5627   DataArrayInt *ret=0;
5628   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5629     {
5630       int tmp2;
5631       ret->getMaxValue(tmp2);
5632       ret->decrRef();
5633       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5634       throw INTERP_KERNEL::Exception(oss.str().c_str());
5635     }
5636   nM1LevMeshIds=ret;
5637   //
5638   revDesc->incrRef();
5639   revDescIndx->incrRef();
5640   ret1->incrRef();
5641   ret0->incrRef();
5642   meshnM1Old2New=ret0;
5643   return ret1;
5644 }
5645
5646 /*!
5647  * This method sorts cell in this so that cells are sorted by cell type specified by MEDMEM and so for MED file.
5648  * It avoids to deal with renum in MEDLoader so it is usefull for MED file R/W with multi types.
5649  * This method returns a newly allocated array old2New.
5650  * This method expects that connectivity of this is set. If not an exception will be thrown. Coordinates are not taken into account.
5651  */
5652 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt() throw(INTERP_KERNEL::Exception)
5653 {
5654   checkConnectivityFullyDefined();
5655   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5656   renumberCells(ret->getConstPointer(),false);
5657   return ret.retn();
5658 }
5659
5660 /*!
5661  * This methods checks that cells are sorted by their types.
5662  * This method makes asumption (no check) that connectivity is correctly set before calling.
5663  */
5664 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5665 {
5666   checkFullyDefined();
5667   const int *conn=_nodal_connec->getConstPointer();
5668   const int *connI=_nodal_connec_index->getConstPointer();
5669   int nbOfCells=getNumberOfCells();
5670   std::set<INTERP_KERNEL::NormalizedCellType> types;
5671   for(const int *i=connI;i!=connI+nbOfCells;)
5672     {
5673       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5674       if(types.find(curType)!=types.end())
5675         return false;
5676       types.insert(curType);
5677       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5678     }
5679   return true;
5680 }
5681
5682 /*!
5683  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5684  * The geometric type order is specified by MED file.
5685  * 
5686  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5687  */
5688 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const throw(INTERP_KERNEL::Exception)
5689 {
5690   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5691 }
5692
5693 /*!
5694  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5695  * that the order is specified in array defined by [orderBg,orderEnd). 
5696  */
5697 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5698 {
5699   checkFullyDefined();
5700   const int *conn=_nodal_connec->getConstPointer();
5701   const int *connI=_nodal_connec_index->getConstPointer();
5702   int nbOfCells=getNumberOfCells();
5703   int lastPos=-1;
5704   for(const int *i=connI;i!=connI+nbOfCells;)
5705     {
5706       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5707       int pos=(int)std::distance(orderBg,std::find(orderBg,orderEnd,curType));
5708       if(pos<=lastPos)
5709         return false;
5710       lastPos=pos;
5711       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5712     }
5713   return true;
5714 }
5715
5716 /*!
5717  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5718  * that tells for each cell the pos of its type in the array on type given in input parameter. The 2nd output parameter is an array with the same
5719  * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurence of type in 'this'.
5720  */
5721 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const throw(INTERP_KERNEL::Exception)
5722 {
5723   checkConnectivityFullyDefined();
5724   int nbOfCells=getNumberOfCells();
5725   const int *conn=_nodal_connec->getConstPointer();
5726   const int *connI=_nodal_connec_index->getConstPointer();
5727   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpa=DataArrayInt::New();
5728   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpb=DataArrayInt::New();
5729   tmpa->alloc(nbOfCells,1);
5730   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5731   tmpb->fillWithZero();
5732   int *tmp=tmpa->getPointer();
5733   int *tmp2=tmpb->getPointer();
5734   for(const int *i=connI;i!=connI+nbOfCells;i++)
5735     {
5736       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5737       if(where!=orderEnd)
5738         {
5739           int pos=(int)std::distance(orderBg,where);
5740           tmp2[pos]++;
5741           tmp[std::distance(connI,i)]=pos;
5742         }
5743       else
5744         {
5745           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5746           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5747           oss << " has a type " << cm.getRepr() << " not in input array of type !";
5748           throw INTERP_KERNEL::Exception(oss.str().c_str());
5749         }
5750     }
5751   nbPerType=tmpb.retn();
5752   return tmpa.retn();
5753 }
5754
5755 /*!
5756  * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [orderBg,orderEnd) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in 'this'.
5757  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5758  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5759  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5760  */
5761 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const throw(INTERP_KERNEL::Exception)
5762 {
5763   DataArrayInt *nbPerType=0;
5764   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5765   nbPerType->decrRef();
5766   return tmpa->buildPermArrPerLevel();
5767 }
5768
5769 /*!
5770  * This method reorganize the cells of 'this' so that the cells with same geometric types are put together.
5771  * The number of cells remains unchanged after the call of this method.
5772  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5773  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5774  *
5775  * @return the array giving the correspondance old to new.
5776  */
5777 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5778 {
5779   checkFullyDefined();
5780   computeTypes();
5781   const int *conn=_nodal_connec->getConstPointer();
5782   const int *connI=_nodal_connec_index->getConstPointer();
5783   int nbOfCells=getNumberOfCells();
5784   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5785   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5786     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5787       {
5788         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5789         types.push_back(curType);
5790         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5791       }
5792   DataArrayInt *ret=DataArrayInt::New();
5793   ret->alloc(nbOfCells,1);
5794   int *retPtr=ret->getPointer();
5795   std::fill(retPtr,retPtr+nbOfCells,-1);
5796   int newCellId=0;
5797   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5798     {
5799       for(const int *i=connI;i!=connI+nbOfCells;i++)
5800         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5801           retPtr[std::distance(connI,i)]=newCellId++;
5802     }
5803   renumberCells(retPtr,false);
5804   return ret;
5805 }
5806
5807 /*!
5808  * This method splits 'this' into as mush as untructured meshes that consecutive set of same type cells.
5809  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5810  * This method makes asumption that connectivity is correctly set before calling.
5811  */
5812 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5813 {
5814   checkFullyDefined();
5815   const int *conn=_nodal_connec->getConstPointer();
5816   const int *connI=_nodal_connec_index->getConstPointer();
5817   int nbOfCells=getNumberOfCells();
5818   std::vector<MEDCouplingUMesh *> ret;
5819   for(const int *i=connI;i!=connI+nbOfCells;)
5820     {
5821       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5822       int beginCellId=(int)std::distance(connI,i);
5823       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5824       int endCellId=(int)std::distance(connI,i);
5825       int sz=endCellId-beginCellId;
5826       int *cells=new int[sz];
5827       for(int j=0;j<sz;j++)
5828         cells[j]=beginCellId+j;
5829       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
5830       delete [] cells;
5831       ret.push_back(m);
5832     }
5833   return ret;
5834 }
5835
5836 /*!
5837  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
5838  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
5839  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
5840  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
5841  * are not used here to avoid the build of big permutation array.
5842  *
5843  * \param [in] ms meshes with same mesh dimension lying on the same coords and sorted by type following de the same geometric type order than
5844  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
5845  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
5846  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
5847  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
5848  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
5849  * \return A newly allocated unstructured mesh that is the result of the aggregation on same coords of all meshes in \b ms. This returned mesh
5850  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
5851  */
5852 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
5853                                                                             DataArrayInt *&szOfCellGrpOfSameType,
5854                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType) throw(INTERP_KERNEL::Exception)
5855 {
5856   std::vector<const MEDCouplingUMesh *> ms2;
5857   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
5858     if(*it)
5859       {
5860         (*it)->checkConnectivityFullyDefined();
5861         ms2.push_back(*it);
5862       }
5863   if(ms2.empty())
5864     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
5865   const DataArrayDouble *refCoo=ms2[0]->getCoords();
5866   int meshDim=ms2[0]->getMeshDimension();
5867   std::vector<const MEDCouplingUMesh *> m1ssm;
5868   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > m1ssmAuto;
5869   //
5870   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
5871   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > m1ssmSingleAuto;
5872   int fake=0,rk=0;
5873   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
5874   ret1->alloc(0,1); ret2->alloc(0,1);
5875   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
5876     {
5877       if(meshDim!=(*it)->getMeshDimension())
5878         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
5879       if(refCoo!=(*it)->getCoords())
5880         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
5881       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
5882       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
5883       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > >(m1ssmAuto));
5884       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
5885         {
5886           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
5887           m1ssmSingleAuto.push_back(singleCell);
5888           m1ssmSingle.push_back(singleCell);
5889           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
5890         }
5891     }
5892   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
5893   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
5894   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
5895   for(std::size_t i=0;i<m1ssm.size();i++)
5896     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
5897   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
5898   szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
5899   idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
5900   return ret0.retn();
5901 }
5902
5903 /*!
5904  * This method returns a newly created DataArrayInt instance.
5905  * This method retrieves cell ids in [begin,end) that have the type 'type'.
5906  */
5907 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const throw(INTERP_KERNEL::Exception)
5908 {
5909   checkFullyDefined();
5910   const int *conn=_nodal_connec->getConstPointer();
5911   const int *connIndex=_nodal_connec_index->getConstPointer();
5912   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
5913   for(const int *w=begin;w!=end;w++)
5914     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
5915       ret->pushBackSilent(*w);
5916   return ret.retn();
5917 }
5918
5919 /*!
5920  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
5921  * are in [0:getNumberOfCells())
5922  */
5923 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const throw(INTERP_KERNEL::Exception)
5924 {
5925   checkFullyDefined();
5926   const int *conn=_nodal_connec->getConstPointer();
5927   const int *connI=_nodal_connec_index->getConstPointer();
5928   int nbOfCells=getNumberOfCells();
5929   std::set<INTERP_KERNEL::NormalizedCellType> types=getAllTypes();
5930   int *tmp=new int[nbOfCells];
5931   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5932     {
5933       int j=0;
5934       for(const int *i=connI;i!=connI+nbOfCells;i++)
5935         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5936           tmp[std::distance(connI,i)]=j++;
5937     }
5938   DataArrayInt *ret=DataArrayInt::New();
5939   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
5940   ret->copyStringInfoFrom(*da);
5941   int *retPtr=ret->getPointer();
5942   const int *daPtr=da->getConstPointer();
5943   int nbOfElems=da->getNbOfElems();
5944   for(int k=0;k<nbOfElems;k++)
5945     retPtr[k]=tmp[daPtr[k]];
5946   delete [] tmp;
5947   return ret;
5948 }
5949
5950 /*!
5951  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
5952  * This method \b works \b for mesh sorted by type.
5953  * cells whose ids is in 'idsPerGeoType' array.
5954  * This method conserves coords and name of mesh.
5955  */
5956 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
5957 {
5958   std::vector<int> code=getDistributionOfTypes();
5959   std::size_t nOfTypesInThis=code.size()/3;
5960   int sz=0,szOfType=0;
5961   for(std::size_t i=0;i<nOfTypesInThis;i++)
5962     {
5963       if(code[3*i]!=type)
5964         sz+=code[3*i+1];
5965       else
5966         szOfType=code[3*i+1];
5967     }
5968   for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
5969     if(*work<0 || *work>=szOfType)
5970       {
5971         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
5972         oss << ". It should be in [0," << szOfType << ") !";
5973         throw INTERP_KERNEL::Exception(oss.str().c_str());
5974       }
5975   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
5976   int *idsPtr=idsTokeep->getPointer();
5977   int offset=0;
5978   for(std::size_t i=0;i<nOfTypesInThis;i++)
5979     {
5980       if(code[3*i]!=type)
5981         for(int j=0;j<code[3*i+1];j++)
5982           *idsPtr++=offset+j;
5983       else
5984         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
5985       offset+=code[3*i+1];
5986     }
5987   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
5988   ret->copyTinyInfoFrom(this);
5989   return ret.retn();
5990 }
5991
5992 /*!
5993  * This method returns a vector of size 'this->getNumberOfCells()'.
5994  * This method retrieves for each cell in 'this' if it is linear (false) or quadratic(true).
5995  */
5996 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const throw(INTERP_KERNEL::Exception)
5997 {
5998   int ncell=getNumberOfCells();
5999   std::vector<bool> ret(ncell);
6000   const int *cI=getNodalConnectivityIndex()->getConstPointer();
6001   const int *c=getNodalConnectivity()->getConstPointer();
6002   for(int i=0;i<ncell;i++)
6003     {
6004       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6005       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6006       ret[i]=cm.isQuadratic();
6007     }
6008   return ret;
6009 }
6010
6011 /*!
6012  * Returns a newly created mesh (with ref count ==1) that contains merge of 'this' and 'other'.
6013  */
6014 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6015 {
6016   if(other->getType()!=UNSTRUCTURED)
6017     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6018   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6019   return MergeUMeshes(this,otherC);
6020 }
6021
6022 /*!
6023  * Returns an array with this->getNumberOfCells() tuples and this->getSpaceDimension() dimension.
6024  * The false barycenter is computed that is to say barycenter of a cell is computed using average on each
6025  * components of coordinates of the cell.
6026  */
6027 DataArrayDouble *MEDCouplingUMesh::getBarycenterAndOwner() const
6028 {
6029   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> ret=DataArrayDouble::New();
6030   int spaceDim=getSpaceDimension();
6031   int nbOfCells=getNumberOfCells();
6032   ret->alloc(nbOfCells,spaceDim);
6033   ret->copyStringInfoFrom(*getCoords());
6034   double *ptToFill=ret->getPointer();
6035   const int *nodal=_nodal_connec->getConstPointer();
6036   const int *nodalI=_nodal_connec_index->getConstPointer();
6037   const double *coor=_coords->getConstPointer();
6038   for(int i=0;i<nbOfCells;i++)
6039     {
6040       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6041       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6042       ptToFill+=spaceDim;
6043     }
6044   return ret.retn();
6045 }
6046
6047 /*!
6048  * This method is similar to MEDCouplingUMesh::getBarycenterAndOwner except that it works on subPart of 'this' without
6049  * building explicitely it. The input part is defined by an array [begin,end). All ids contained in this array should be less than this->getNumberOfCells().
6050  * No check of that will be done !
6051  */
6052 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
6053 {
6054   DataArrayDouble *ret=DataArrayDouble::New();
6055   int spaceDim=getSpaceDimension();
6056   int nbOfTuple=(int)std::distance(begin,end);
6057   ret->alloc(nbOfTuple,spaceDim);
6058   double *ptToFill=ret->getPointer();
6059   double *tmp=new double[spaceDim];
6060   const int *nodal=_nodal_connec->getConstPointer();
6061   const int *nodalI=_nodal_connec_index->getConstPointer();
6062   const double *coor=_coords->getConstPointer();
6063   for(const int *w=begin;w!=end;w++)
6064     {
6065       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6066       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6067       ptToFill+=spaceDim;
6068     }
6069   delete [] tmp;
6070   return ret;
6071 }
6072
6073 /*!
6074  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6075  * 
6076  */
6077 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da) throw(INTERP_KERNEL::Exception)
6078 {
6079   if(!da)
6080     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6081   da->checkAllocated();
6082   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName().c_str(),0);
6083   ret->setCoords(da);
6084   int nbOfTuples=da->getNumberOfTuples();
6085   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
6086   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
6087   c->alloc(2*nbOfTuples,1);
6088   cI->alloc(nbOfTuples+1,1);
6089   int *cp=c->getPointer();
6090   int *cip=cI->getPointer();
6091   *cip++=0;
6092   for(int i=0;i<nbOfTuples;i++)
6093     {
6094       *cp++=INTERP_KERNEL::NORM_POINT1;
6095       *cp++=i;
6096       *cip++=2*(i+1);
6097     }
6098   ret->setConnectivity(c,cI,true);
6099   return ret.retn();
6100 }
6101
6102 /*!
6103  * Returns a newly created mesh (with ref count ==1) that contains merge of 'mesh1' and 'other'.
6104  * The coords of 'mesh2' are added at the end of coords of 'mesh1'.
6105  */
6106 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception)
6107 {
6108   std::vector<const MEDCouplingUMesh *> tmp(2);
6109   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6110   return MergeUMeshes(tmp);
6111 }
6112
6113 /*!
6114  * This method returns in case of success a mesh constitued from union of all meshes in 'a'.
6115  * There should be \b no presence of null pointer into 'a'. If any an INTERP_KERNEL::Exception will be thrown.
6116  * The returned mesh will contain aggregation of nodes in 'a' (in the same order) and aggregation of
6117  * cells in meshes in 'a' (in the same order too).
6118  */
6119 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a) throw(INTERP_KERNEL::Exception)
6120 {
6121   std::size_t sz=a.size();
6122   if(sz==0)
6123     return MergeUMeshesLL(a);
6124   for(std::size_t ii=0;ii<sz;ii++)
6125     if(!a[ii])
6126       {
6127         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6128         throw INTERP_KERNEL::Exception(oss.str().c_str());
6129       }
6130   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > bb(sz);
6131   std::vector< const MEDCouplingUMesh * > aa(sz);
6132   int spaceDim=-3;
6133   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6134     {
6135       const MEDCouplingUMesh *cur=a[i];
6136       const DataArrayDouble *coo=cur->getCoords();
6137       if(coo)
6138         spaceDim=coo->getNumberOfComponents();
6139     }
6140   if(spaceDim==-3)
6141     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6142   for(std::size_t i=0;i<sz;i++)
6143     {
6144       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6145       aa[i]=bb[i];
6146     }
6147   return MergeUMeshesLL(aa);
6148 }
6149
6150 /// @cond INTERNAL
6151
6152 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a) throw(INTERP_KERNEL::Exception)
6153 {
6154   if(a.empty())
6155     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
6156   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
6157   int meshDim=(*it)->getMeshDimension();
6158   int nbOfCells=(*it)->getNumberOfCells();
6159   int meshLgth=(*it++)->getMeshLength();
6160   for(;it!=a.end();it++)
6161     {
6162       if(meshDim!=(*it)->getMeshDimension())
6163         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
6164       nbOfCells+=(*it)->getNumberOfCells();
6165       meshLgth+=(*it)->getMeshLength();
6166     }
6167   std::vector<const MEDCouplingPointSet *> aps(a.size());
6168   std::copy(a.begin(),a.end(),aps.begin());
6169   DataArrayDouble *pts=MergeNodesArray(aps);
6170   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
6171   ret->setCoords(pts);
6172   pts->decrRef();
6173   DataArrayInt *c=DataArrayInt::New();
6174   c->alloc(meshLgth,1);
6175   int *cPtr=c->getPointer();
6176   DataArrayInt *cI=DataArrayInt::New();
6177   cI->alloc(nbOfCells+1,1);
6178   int *cIPtr=cI->getPointer();
6179   *cIPtr++=0;
6180   int offset=0;
6181   int offset2=0;
6182   for(it=a.begin();it!=a.end();it++)
6183     {
6184       int curNbOfCell=(*it)->getNumberOfCells();
6185       const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
6186       const int *curC=(*it)->_nodal_connec->getConstPointer();
6187       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
6188       for(int j=0;j<curNbOfCell;j++)
6189         {
6190           const int *src=curC+curCI[j];
6191           *cPtr++=*src++;
6192           for(;src!=curC+curCI[j+1];src++,cPtr++)
6193             {
6194               if(*src!=-1)
6195                 *cPtr=*src+offset2;
6196               else
6197                 *cPtr=-1;
6198             }
6199         }
6200       offset+=curCI[curNbOfCell];
6201       offset2+=(*it)->getNumberOfNodes();
6202     }
6203   //
6204   ret->setConnectivity(c,cI,true);
6205   c->decrRef();
6206   cI->decrRef();
6207   return ret.retn();
6208 }
6209
6210 /// @endcond
6211
6212 /*!
6213  * Idem MergeUMeshes except that 'meshes' are expected to lyie on the same coords and 'meshes' have the same meshdim.
6214  * 'meshes' must be a non empty vector.
6215  */
6216 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception)
6217 {
6218   std::vector<const MEDCouplingUMesh *> tmp(2);
6219   tmp[0]=mesh1; tmp[1]=mesh2;
6220   return MergeUMeshesOnSameCoords(tmp);
6221 }
6222
6223 /*!
6224  * Idem MergeUMeshes except that 'meshes' are expected to lyie on the same coords and 'meshes' have the same meshdim.
6225  * 'meshes' must be a non empty vector.
6226  */
6227 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6228 {
6229   if(meshes.empty())
6230     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6231   for(std::size_t ii=0;ii<meshes.size();ii++)
6232     if(!meshes[ii])
6233       {
6234         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6235         throw INTERP_KERNEL::Exception(oss.str().c_str());
6236       }
6237   const DataArrayDouble *coords=meshes.front()->getCoords();
6238   int meshDim=meshes.front()->getMeshDimension();
6239   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6240   int meshLgth=0;
6241   int meshIndexLgth=0;
6242   for(;iter!=meshes.end();iter++)
6243     {
6244       if(coords!=(*iter)->getCoords())
6245         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6246       if(meshDim!=(*iter)->getMeshDimension())
6247         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6248       meshLgth+=(*iter)->getMeshLength();
6249       meshIndexLgth+=(*iter)->getNumberOfCells();
6250     }
6251   DataArrayInt *nodal=DataArrayInt::New();
6252   nodal->alloc(meshLgth,1);
6253   int *nodalPtr=nodal->getPointer();
6254   DataArrayInt *nodalIndex=DataArrayInt::New();
6255   nodalIndex->alloc(meshIndexLgth+1,1);
6256   int *nodalIndexPtr=nodalIndex->getPointer();
6257   int offset=0;
6258   for(iter=meshes.begin();iter!=meshes.end();iter++)
6259     {
6260       const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
6261       const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
6262       int nbOfCells=(*iter)->getNumberOfCells();
6263       int meshLgth2=(*iter)->getMeshLength();
6264       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6265       if(iter!=meshes.begin())
6266         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
6267       else
6268         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6269       offset+=meshLgth2;
6270     }
6271   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6272   ret->setName("merge");
6273   ret->setMeshDimension(meshDim);
6274   ret->setConnectivity(nodal,nodalIndex,true);
6275   ret->setCoords(coords);
6276   nodalIndex->decrRef();
6277   nodal->decrRef();
6278   return ret;
6279 }
6280
6281 /*!
6282  * This method fuses meshes 'meshes' and returns the fused mesh and the correspondances arrays for each mesh in 'meshes' in returned mesh.
6283  * If a same cell is detected in several meshes in 'meshes', this cell will appear only once in returned mesh (see ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer for more details)
6284  *
6285  * @param meshes input non empty vector containing meshes having same coordiantes array and same mesh dimension.
6286  * @param compType see MEDCouplingUMesh::zipConnectivityTraducer
6287  * @param corr output vector with same size as 'meshes' parameter. corr[i] is the correspondance array of mesh meshes[i] in returned mesh.
6288  *             The arrays contained in 'corr' parameter are returned with refcounter set to one.
6289  *             To avoid memory leaks the caller have to deal with each instances of DataArrayInt contained in 'corr' parameter.
6290  * @return The mesh lying on the same coordinates than those in meshes. All cells in 'meshes' are in returned mesh with 
6291  * @exception if meshes is a empty vector or meshes are not lying on same coordinates or meshes not have the same dimension.
6292  */
6293 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
6294 {
6295   //All checks are delegated to MergeUMeshesOnSameCoords
6296   MEDCouplingUMesh *ret=MergeUMeshesOnSameCoords(meshes);
6297   DataArrayInt *o2n=ret->zipConnectivityTraducer(compType);
6298   corr.resize(meshes.size());
6299   std::size_t nbOfMeshes=meshes.size();
6300   int offset=0;
6301   const int *o2nPtr=o2n->getConstPointer();
6302   for(std::size_t i=0;i<nbOfMeshes;i++)
6303     {
6304       DataArrayInt *tmp=DataArrayInt::New();
6305       int curNbOfCells=meshes[i]->getNumberOfCells();
6306       tmp->alloc(curNbOfCells,1);
6307       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6308       offset+=curNbOfCells;
6309       tmp->setName(meshes[i]->getName());
6310       corr[i]=tmp;
6311     }
6312   o2n->decrRef();
6313   return ret;
6314 }
6315
6316 /*!
6317  * This method takes in input meshes \b meshes containing no null reference. If any an INTERP_KERNEL::Exception will be thrown.
6318  * \b meshes should have a good coherency (connectivity and coordinates well defined).
6319  * All mesh in \b meshes must have the same space dimension. If not an INTERP_KERNEL:Exception will be thrown.
6320  * But mesh in \b meshes \b can \b have \b different \b mesh \b dimension \b each \b other.
6321  *
6322  * This method performs nothing if size of \b meshes is in [0,1].
6323  * This method is particulary usefull in MEDLoader context to build a \ref ParaMEDMEM::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6324  * coordinates DataArrayDouble instance.
6325  *
6326  * \param [in,out] meshes : vector containing no null instance of MEDCouplingUMesh that in case of success of this method will be modified.
6327  */
6328 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes) throw(INTERP_KERNEL::Exception)
6329 {
6330   std::size_t sz=meshes.size();
6331   if(sz==0 || sz==1)
6332     return;
6333   std::vector< const DataArrayDouble * > coords(meshes.size());
6334   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6335   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6336     {
6337       if((*it))
6338         {
6339           (*it)->checkConnectivityFullyDefined();
6340           const DataArrayDouble *coo=(*it)->getCoords();
6341           if(coo)
6342             *it2=coo;
6343           else
6344             {
6345               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6346               oss << " has no coordinate array defined !";
6347               throw INTERP_KERNEL::Exception(oss.str().c_str());
6348             }
6349         }
6350       else
6351         {
6352           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6353           oss << " is null !";
6354           throw INTERP_KERNEL::Exception(oss.str().c_str());
6355         }
6356     }
6357   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6358   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6359   int offset=(*it)->getNumberOfNodes();
6360   (*it++)->setCoords(res);
6361   for(;it!=meshes.end();it++)
6362     {
6363       int oldNumberOfNodes=(*it)->getNumberOfNodes();
6364       (*it)->setCoords(res);
6365       (*it)->shiftNodeNumbersInConn(offset);
6366       offset+=oldNumberOfNodes;
6367     }
6368 }
6369
6370 /*!
6371  * This method takes in input meshes \b meshes containing no null reference. If any an INTERP_KERNEL::Exception will be thrown.
6372  * \b meshes should have a good coherency (connectivity and coordinates well defined).
6373  * All mesh in \b meshes must have the same space dimension. If not an INTERP_KERNEL:Exception will be thrown.
6374  * But mesh in \b meshes \b can \b have \b different \b mesh \b dimension \b each \b other.
6375  * If \b meshes share the same instance of DataArrayDouble as coordinates and that this instance is null, this method do nothing and no exception will be thrown.
6376  *
6377  * This method performs nothing if size of \b meshes is empty.
6378  * This method is particulary usefull in MEDLoader context to perform a treatment of a MEDFileUMesh instance on different levels.
6379  * coordinates DataArrayDouble instance.
6380  *
6381  * \param [in,out] meshes :vector containing no null instance of MEDCouplingUMesh sharing the same DataArrayDouble instance of coordinates, that in case of success of this method will be modified.
6382  * \param [in] eps is the distance in absolute (that should be positive !), so that 2 or more points within a distance of eps will be merged into a single point.
6383  */
6384 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps) throw(INTERP_KERNEL::Exception)
6385 {
6386   if(meshes.empty())
6387     return ;
6388   std::set<const DataArrayDouble *> s;
6389   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6390     {
6391       if(*it)
6392         s.insert((*it)->getCoords());
6393       else
6394         {
6395           std::ostringstream oss; oss << "MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords : In input vector of unstructured meshes of size " << meshes.size() << " the element #" << std::distance(meshes.begin(),it) << " is null !";
6396           throw INTERP_KERNEL::Exception(oss.str().c_str());
6397         }
6398     }
6399   if(s.size()!=1)
6400     {
6401       std::ostringstream oss; oss << "MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords : In input vector of unstructured meshes of size " << meshes.size() << ", it appears that they do not share the same instance of DataArrayDouble for coordiantes ! tryToShareSameCoordsPermute method can help to reach that !";
6402       throw INTERP_KERNEL::Exception(oss.str().c_str());
6403     }
6404   const DataArrayDouble *coo=*(s.begin());
6405   if(!coo)
6406     return;
6407   //
6408   DataArrayInt *comm,*commI;
6409   coo->findCommonTuples(eps,-1,comm,commI);
6410   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1(comm),tmp2(commI);
6411   int oldNbOfNodes=coo->getNumberOfTuples();
6412   int newNbOfNodes;
6413   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
6414   if(oldNbOfNodes==newNbOfNodes)
6415     return ;
6416   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
6417   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6418     {
6419       (*it)->renumberNodesInConn(o2n->getConstPointer());
6420       (*it)->setCoords(newCoords);
6421     } 
6422 }
6423
6424 /*!
6425  * This method takes in input a cell defined by its MEDcouplingUMesh connectivity [connBg,connEnd) and returns its extruded cell by inserting the result at the end of ret.
6426  * @param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
6427  * @param isQuad specifies the policy of connectivity.
6428  * @ret in/out parameter in which the result will be append
6429  */
6430 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
6431 {
6432   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
6433   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
6434   ret.push_back(cm.getExtrudedType());
6435   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
6436   switch(flatType)
6437     {
6438     case INTERP_KERNEL::NORM_POINT1:
6439       {
6440         ret.push_back(connBg[1]);
6441         ret.push_back(connBg[1]+nbOfNodesPerLev);
6442         break;
6443       }
6444     case INTERP_KERNEL::NORM_SEG2:
6445       {
6446         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
6447         ret.insert(ret.end(),conn,conn+4);
6448         break;
6449       }
6450     case INTERP_KERNEL::NORM_SEG3:
6451       {
6452         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
6453         ret.insert(ret.end(),conn,conn+8);
6454         break;
6455       }
6456     case INTERP_KERNEL::NORM_QUAD4:
6457       {
6458         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
6459         ret.insert(ret.end(),conn,conn+8);
6460         break;
6461       }
6462     case INTERP_KERNEL::NORM_TRI3:
6463       {
6464         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
6465         ret.insert(ret.end(),conn,conn+6);
6466         break;
6467       }
6468     case INTERP_KERNEL::NORM_TRI6:
6469       {
6470         int conn[15]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4],connBg[5],connBg[6],connBg[4]+deltaz,connBg[5]+deltaz,connBg[6]+deltaz,
6471                       connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
6472         ret.insert(ret.end(),conn,conn+15);
6473         break;
6474       }
6475     case INTERP_KERNEL::NORM_QUAD8:
6476       {
6477         int conn[20]={
6478           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
6479           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
6480           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
6481         };
6482         ret.insert(ret.end(),conn,conn+20);
6483         break;
6484       }
6485     case INTERP_KERNEL::NORM_POLYGON:
6486       {
6487         std::back_insert_iterator< std::vector<int> > ii(ret);
6488         std::copy(connBg+1,connEnd,ii);
6489         *ii++=-1;
6490         std::reverse_iterator<const int *> rConnBg(connEnd);
6491         std::reverse_iterator<const int *> rConnEnd(connBg+1);
6492         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
6493         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
6494         for(std::size_t i=0;i<nbOfRadFaces;i++)
6495           {
6496             *ii++=-1;
6497             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
6498             std::copy(conn,conn+4,ii);
6499           }
6500         break;
6501       }
6502     default:
6503       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
6504     }
6505 }
6506
6507 /*!
6508  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [begin,end).
6509  */
6510 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6511 {
6512   double v[3]={0.,0.,0.};
6513   std::size_t sz=std::distance(begin,end);
6514   if(isQuadratic)
6515     sz/=2;
6516   for(std::size_t i=0;i<sz;i++)
6517     {
6518       v[0]+=coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]+2]-coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]+1];
6519       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6520       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6521     }
6522   return vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2]>0.;
6523 }
6524
6525 /*!
6526  * The polyhedron is specfied by its connectivity nodes in [begin,end).
6527  */
6528 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6529 {
6530   std::vector<std::pair<int,int> > edges;
6531   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6532   const int *bgFace=begin;
6533   for(std::size_t i=0;i<nbOfFaces;i++)
6534     {
6535       const int *endFace=std::find(bgFace+1,end,-1);
6536       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6537       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6538         {
6539           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6540           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6541             return false;
6542           edges.push_back(p1);
6543         }
6544       bgFace=endFace+1;
6545     }
6546   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6547 }
6548
6549 /*!
6550  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [begin,end).
6551  */
6552 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
6553 {
6554   double vec0[3],vec1[3];
6555   std::size_t sz=std::distance(begin,end);
6556   if(sz%2!=0)
6557     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
6558   int nbOfNodes=(int)sz/2;
6559   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
6560   const double *pt0=coords+3*begin[0];
6561   const double *pt1=coords+3*begin[nbOfNodes];
6562   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
6563   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
6564 }
6565
6566 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
6567 {
6568   std::size_t sz=std::distance(begin,end);
6569   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6570   std::size_t nbOfNodes(sz/2);
6571   std::copy(begin,end,(int *)tmp);
6572   for(std::size_t j=1;j<nbOfNodes;j++)
6573     {
6574       begin[j]=tmp[nbOfNodes-j];
6575       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
6576     }
6577 }
6578
6579 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
6580 {
6581   std::size_t sz=std::distance(begin,end);
6582   if(sz!=4)
6583     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkCoherency2 !");
6584   double vec0[3],vec1[3];
6585   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
6586   vec0[0]=pt1[0]-pt0[0]; vec0[1]=pt1[1]-pt0[1]; vec0[2]=pt1[2]-pt0[2]; vec1[0]=pt2[0]-pt0[0]; vec1[1]=pt2[1]-pt0[1]; vec1[2]=pt2[2]-pt0[2]; 
6587   return ((vec0[1]*vec1[2]-vec0[2]*vec1[1])*(pt3[0]-pt0[0])+(vec0[2]*vec1[0]-vec0[0]*vec1[2])*(pt3[1]-pt0[1])+(vec0[0]*vec1[1]-vec0[1]*vec1[0])*(pt3[2]-pt0[2]))<0;
6588 }
6589
6590 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
6591 {
6592   std::size_t sz=std::distance(begin,end);
6593   if(sz!=5)
6594     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkCoherency2 !");
6595   double vec0[3];
6596   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
6597   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
6598   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
6599 }
6600
6601 /*!
6602  * This method performs a simplyfication of a single polyedron cell. To do that each face of cell whose connectivity is defined by [\b begin, \b end) 
6603  * is compared with the others in order to find faces in the same plane (with approx of eps). If any, the cells are grouped together and projected to
6604  * a 2D space.
6605  *
6606  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
6607  * \param [in] coords the coordinates with nb of components exactly equal to 3
6608  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
6609  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
6610  * \param [out] res the result is put at the end of the vector without any alteration of the data.
6611  */
6612 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res) throw(INTERP_KERNEL::Exception)
6613 {
6614   int nbFaces=std::count(begin+1,end,-1)+1;
6615   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
6616   double *vPtr=v->getPointer();
6617   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
6618   double *pPtr=p->getPointer();
6619   const int *stFaceConn=begin+1;
6620   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
6621     {
6622       const int *endFaceConn=std::find(stFaceConn,end,-1);
6623       ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
6624       stFaceConn=endFaceConn+1;
6625     }
6626   pPtr=p->getPointer(); vPtr=v->getPointer();
6627   DataArrayInt *comm1=0,*commI1=0;
6628   v->findCommonTuples(eps,-1,comm1,commI1);
6629   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
6630   const int *comm1Ptr=comm1->getConstPointer();
6631   const int *commI1Ptr=commI1->getConstPointer();
6632   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
6633   res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
6634   //
6635   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
6636   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
6637   mm->finishInsertingCells();
6638   //
6639   for(int i=0;i<nbOfGrps1;i++)
6640     {
6641       int vecId=comm1Ptr[commI1Ptr[i]];
6642       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6643       DataArrayInt *comm2=0,*commI2=0;
6644       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
6645       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
6646       const int *comm2Ptr=comm2->getConstPointer();
6647       const int *commI2Ptr=commI2->getConstPointer();
6648       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
6649       for(int j=0;j<nbOfGrps2;j++)
6650         {
6651           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
6652             {
6653               res->insertAtTheEnd(begin,end);
6654               res->pushBackSilent(-1);
6655             }
6656           else
6657             {
6658               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
6659               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids2=comm2->selectByTupleId2(commI2Ptr[j],commI2Ptr[j+1],1);
6660               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6661               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
6662               MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
6663               MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
6664               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
6665               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
6666               const int *idsNodePtr=idsNode->getConstPointer();
6667               double center[3]; center[0]=pPtr[pointId]*vPtr[3*vecId]; center[1]=pPtr[pointId]*vPtr[3*vecId+1]; center[2]=pPtr[pointId]*vPtr[3*vecId+2];
6668               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
6669               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
6670               if(std::abs(norm)>eps)
6671                 {
6672                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
6673                   mm3->rotate(center,vec,angle);
6674                 }
6675               mm3->changeSpaceDimension(2);
6676               MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
6677               const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
6678               const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
6679               int nbOfCells=mm4->getNumberOfCells();
6680               for(int k=0;k<nbOfCells;k++)
6681                 {
6682                   int l=0;
6683                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
6684                     res->pushBackSilent(idsNodePtr[*work]);
6685                   res->pushBackSilent(-1);
6686                 }
6687             }
6688         }
6689     }
6690   res->popBackSilent();
6691 }
6692
6693 /*!
6694  * This method computes the normalized vector of the plane and the pos of the point belonging to the plane and the line defined by the vector going
6695  * through origin. The plane is defined by its nodal connectivity [\b begin, \b end).
6696  * 
6697  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
6698  * \param [in] coords coordinates expected to have 3 components.
6699  * \param [in] begin start of the nodal connectivity of the face.
6700  * \param [in] end end of the nodal connectivity (excluded) of the face.
6701  * \param [out] v the normalized vector of size 3
6702  * \param [out] p the pos of plane
6703  */
6704 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p) throw(INTERP_KERNEL::Exception)
6705 {
6706   std::size_t nbPoints=std::distance(begin,end);
6707   if(nbPoints<3)
6708     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
6709   double vec[3];
6710   std::size_t j=0;
6711   bool refFound=false;
6712   for(;j<nbPoints-1 && !refFound;j++)
6713     {
6714       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
6715       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
6716       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
6717       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
6718       if(norm>eps)
6719         {
6720           refFound=true;
6721           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
6722         }
6723     }
6724   for(std::size_t i=j;i<nbPoints-1;i++)
6725     {
6726       double curVec[3];
6727       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
6728       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
6729       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
6730       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
6731       if(norm<eps)
6732         continue;
6733       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
6734       v[0]=vec[1]*curVec[2]-vec[2]*curVec[1]; v[1]=vec[2]*curVec[0]-vec[0]*curVec[2]; v[2]=vec[0]*curVec[1]-vec[1]*curVec[0];
6735       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
6736       if(norm>eps)
6737         {
6738           v[0]/=norm; v[1]/=norm; v[2]/=norm;
6739           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
6740           return ;
6741         }
6742     }
6743   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
6744 }
6745
6746 /*!
6747  * This method tries to obtain a well oriented polyhedron.
6748  * If the algorithm fails, an exception will be thrown.
6749  */
6750 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords) throw(INTERP_KERNEL::Exception)
6751 {
6752   std::list< std::pair<int,int> > edgesOK,edgesFinished;
6753   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6754   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
6755   isPerm[0]=true;
6756   int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
6757   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6758   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
6759   //
6760   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
6761     {
6762       bgFace=begin;
6763       std::size_t smthChanged=0;
6764       for(std::size_t i=0;i<nbOfFaces;i++)
6765         {
6766           endFace=std::find(bgFace+1,end,-1);
6767           nbOfEdgesInFace=std::distance(bgFace,endFace);
6768           if(!isPerm[i])
6769             {
6770               bool b;
6771               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6772                 {
6773                   std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6774                   std::pair<int,int> p2(p1.second,p1.first);
6775                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
6776                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
6777                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
6778                 }
6779               if(isPerm[i])
6780                 { 
6781                   if(!b)
6782                     std::reverse(bgFace+1,endFace);
6783                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6784                     {
6785                       std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6786                       std::pair<int,int> p2(p1.second,p1.first);
6787                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
6788                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
6789                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
6790                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
6791                       std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
6792                       if(it!=edgesOK.end())
6793                         {
6794                           edgesOK.erase(it);
6795                           edgesFinished.push_back(p1);
6796                         }
6797                       else
6798                         edgesOK.push_back(p1);
6799                     }
6800                 }
6801             }
6802           bgFace=endFace+1;
6803         }
6804       if(smthChanged==0)
6805         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
6806     }
6807   if(!edgesOK.empty())
6808     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
6809   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
6810     {//not lucky ! The first face was not correctly oriented : reorient all faces...
6811       bgFace=begin;
6812       for(std::size_t i=0;i<nbOfFaces;i++)
6813         {
6814           endFace=std::find(bgFace+1,end,-1);
6815           std::reverse(bgFace+1,endFace);
6816           bgFace=endFace+1;
6817         }
6818     }
6819 }
6820
6821 /*!
6822  * This method makes the assumption spacedimension == meshdimension == 2.
6823  * This method works only for linear cells.
6824  * 
6825  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
6826  */
6827 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const throw(INTERP_KERNEL::Exception)
6828 {
6829   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
6830     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
6831   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=computeSkin();
6832   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=m->zipCoordsTraducer();
6833   int nbOfNodesExpected=m->getNumberOfNodes();
6834   if(m->getNumberOfCells()!=nbOfNodesExpected)
6835     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part or a quadratic 2D mesh !");
6836   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(m->getNumberOfNodes());
6837   const int *n2oPtr=n2o->getConstPointer();
6838   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
6839   m->getReverseNodalConnectivity(revNodal,revNodalI);
6840   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
6841   const int *nodalPtr=m->getNodalConnectivity()->getConstPointer();
6842   const int *nodalIPtr=m->getNodalConnectivityIndex()->getConstPointer();
6843   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(nbOfNodesExpected+1,1);
6844   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYGON;
6845   if(nbOfNodesExpected<1)
6846     return ret.retn();
6847   int prevCell=0;
6848   int prevNode=nodalPtr[nodalIPtr[0]+1];
6849   *work++=n2oPtr[prevNode];
6850   for(int i=1;i<nbOfNodesExpected;i++)
6851     {
6852       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
6853         {
6854           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
6855           conn.erase(prevNode);
6856           if(conn.size()==1)
6857             {
6858               int curNode=*(conn.begin());
6859               *work++=n2oPtr[curNode];
6860               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
6861               shar.erase(prevCell);
6862               if(shar.size()==1)
6863                 {
6864                   prevCell=*(shar.begin());
6865                   prevNode=curNode;
6866                 }
6867               else
6868                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected 2 !");
6869             }
6870           else
6871             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected 1 !");
6872         }
6873       else
6874         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected cell !");
6875     }
6876   return ret.retn();
6877 }
6878
6879 /*!
6880  * This method makes the assumption spacedimension == meshdimension == 3.
6881  * This method works only for linear cells.
6882  * 
6883  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
6884  */
6885 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const throw(INTERP_KERNEL::Exception)
6886 {
6887   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6888     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
6889   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=computeSkin();
6890   const int *conn=m->getNodalConnectivity()->getConstPointer();
6891   const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
6892   int nbOfCells=m->getNumberOfCells();
6893   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
6894   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
6895   if(nbOfCells<1)
6896     return ret.retn();
6897   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
6898   for(int i=1;i<nbOfCells;i++)
6899     {
6900       *work++=-1;
6901       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
6902     }
6903   return ret.retn();
6904 }
6905
6906 /*!
6907  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
6908  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
6909  */
6910 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt) throw(INTERP_KERNEL::Exception)
6911 {
6912   double *w=zipFrmt;
6913   if(spaceDim==3)
6914     for(int i=0;i<nbOfNodesInCell;i++)
6915       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
6916   else if(spaceDim==2)
6917     {
6918       for(int i=0;i<nbOfNodesInCell;i++)
6919         {
6920           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
6921           *w++=0.;
6922         }
6923     }
6924   else
6925     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
6926 }
6927
6928 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData) const throw(INTERP_KERNEL::Exception)
6929 {
6930   int nbOfCells=getNumberOfCells();
6931   if(nbOfCells<=0)
6932     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
6933   static const int PARAMEDMEM2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,-1,23,-1,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,-1,-1,-1,25,42,-1,4};
6934   ofs << "  <" << getVTKDataSetType() << ">\n";
6935   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
6936   ofs << "      <PointData>\n" << pointData << std::endl;
6937   ofs << "      </PointData>\n";
6938   ofs << "      <CellData>\n" << cellData << std::endl;
6939   ofs << "      </CellData>\n";
6940   ofs << "      <Points>\n";
6941   if(getSpaceDimension()==3)
6942     _coords->writeVTK(ofs,8,"Points");
6943   else
6944     {
6945       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
6946       coo->writeVTK(ofs,8,"Points");
6947     }
6948   ofs << "      </Points>\n";
6949   ofs << "      <Cells>\n";
6950   const int *cPtr=_nodal_connec->getConstPointer();
6951   const int *cIPtr=_nodal_connec_index->getConstPointer();
6952   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
6953   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
6954   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
6955   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
6956   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
6957   int szFaceOffsets=0,szConn=0;
6958   for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
6959     {
6960       *w2=cPtr[cIPtr[i]];
6961       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
6962         {
6963           *w1=-1;
6964           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
6965           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
6966         }
6967       else
6968         {
6969           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
6970           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
6971           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
6972           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
6973           w4=std::copy(c.begin(),c.end(),w4);
6974         }
6975     }
6976   types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE);
6977   types->writeVTK(ofs,8,"UInt8","types");
6978   offsets->writeVTK(ofs,8,"Int32","offsets");
6979   if(szFaceOffsets!=0)
6980     {//presence of Polyhedra
6981       connectivity->reAlloc(szConn);
6982       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets");
6983       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
6984       w1=faces->getPointer();
6985       for(int i=0;i<nbOfCells;i++)
6986         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
6987           {
6988             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
6989             *w1++=nbFaces;
6990             const int *w6=cPtr+cIPtr[i]+1,*w5=0;
6991             for(int j=0;j<nbFaces;j++)
6992               {
6993                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
6994                 *w1++=(int)std::distance(w6,w5);
6995                 w1=std::copy(w6,w5,w1);
6996                 w6=w5+1;
6997               }
6998           }
6999       faces->writeVTK(ofs,8,"Int32","faces");
7000     }
7001   connectivity->writeVTK(ofs,8,"Int32","connectivity");
7002   ofs << "      </Cells>\n";
7003   ofs << "    </Piece>\n";
7004   ofs << "  </" << getVTKDataSetType() << ">\n";
7005 }
7006
7007 std::string MEDCouplingUMesh::getVTKDataSetType() const throw(INTERP_KERNEL::Exception)
7008 {
7009   return std::string("UnstructuredGrid");
7010 }
7011
7012 /// @cond INTERNAL
7013
7014 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2) throw(INTERP_KERNEL::Exception)
7015 {
7016   m1->checkFullyDefined();
7017   m2->checkFullyDefined();
7018   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
7019     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
7020   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
7021   MEDCouplingUMesh *m1Desc=0,*m2Desc=0;
7022   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
7023   std::vector<double> addCoo,addCoordsQuadratic;
7024   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
7025   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
7026   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
7027                               m2Desc,desc2,descIndx2,revDesc2,revDescIndx2,addCoo);
7028   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
7029   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
7030   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
7031   std::vector< std::vector<int> > intersectEdge2;
7032   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
7033   subDiv2.clear(); dd5=0; dd6=0;
7034   std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
7035   std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
7036   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
7037                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
7038   //
7039   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> addCooDa=DataArrayDouble::New();
7040   addCooDa->alloc((int)(addCoo.size())/2,2);
7041   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
7042   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> addCoordsQuadraticDa=DataArrayDouble::New();
7043   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
7044   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
7045   std::vector<const DataArrayDouble *> coordss(4);
7046   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
7047   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=DataArrayDouble::Aggregate(coordss);
7048   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Intersect2D",2);
7049   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> conn=DataArrayInt::New(); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
7050   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connI=DataArrayInt::New(); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
7051   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c1=DataArrayInt::New(); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
7052   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c2=DataArrayInt::New(); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
7053   ret->setConnectivity(conn,connI,true);
7054   ret->setCoords(coo);
7055   cellNb1=c1.retn(); cellNb2=c2.retn();
7056   return ret.retn();
7057 }
7058
7059 /// @endcond
7060
7061 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
7062                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
7063                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
7064                                                          const std::vector<double>& addCoords,
7065                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
7066 {
7067   static const int SPACEDIM=2;
7068   std::vector<double> bbox1,bbox2;
7069   const double *coo1=m1->getCoords()->getConstPointer();
7070   const int *conn1=m1->getNodalConnectivity()->getConstPointer();
7071   const int *connI1=m1->getNodalConnectivityIndex()->getConstPointer();
7072   int offset1=m1->getNumberOfNodes();
7073   const double *coo2=m2->getCoords()->getConstPointer();
7074   const int *conn2=m2->getNodalConnectivity()->getConstPointer();
7075   const int *connI2=m2->getNodalConnectivityIndex()->getConstPointer();
7076   int offset2=offset1+m2->getNumberOfNodes();
7077   int offset3=offset2+((int)addCoords.size())/2;
7078   m1->getBoundingBoxForBBTree(bbox1);
7079   m2->getBoundingBoxForBBTree(bbox2);
7080   BBTree<SPACEDIM,int> myTree(&bbox2[0],0,0,m2->getNumberOfCells(),eps);
7081   int ncell1=m1->getNumberOfCells();
7082   crI.push_back(0);
7083   for(int i=0;i<ncell1;i++)
7084     {
7085       std::vector<int> candidates2;
7086       myTree.getIntersectingElems(&bbox1[i*2*SPACEDIM],candidates2);
7087       std::map<INTERP_KERNEL::Node *,int> mapp;
7088       std::map<int,INTERP_KERNEL::Node *> mappRev;
7089       INTERP_KERNEL::QuadraticPolygon pol1;
7090       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
7091       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7092       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
7093       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
7094                                    desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
7095       //
7096       std::set<INTERP_KERNEL::Edge *> edges1;// store all edges of pol1 that are NOT consumed by intersect cells. If any after iteration over candidates2 -> a part of pol1 should appear in result
7097       std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
7098       INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
7099       for(it1.first();!it1.finished();it1.next())
7100         edges1.insert(it1.current()->getPtr());
7101       //
7102       std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare;
7103       std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
7104       int ii=0;
7105       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
7106         {
7107           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
7108           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
7109           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
7110           pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
7111                                              pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2,edgesIn2ForShare);
7112         }
7113       ii=0;
7114       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
7115         {
7116           pol1.initLocationsWithOther(pol2s[ii]);
7117           pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
7118           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
7119           pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
7120         }
7121       if(!edges1.empty())
7122         {
7123           try
7124             {
7125               INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
7126             }
7127           catch(INTERP_KERNEL::Exception& e)
7128             {
7129               std::ostringstream oss; oss << "Error when computing residual of cell #" << i << " in source/m1 mesh ! Maybe the neighbours of this cell in mesh are not well connected !\n" << "The deep reason is the following : " << e.what();
7130               throw INTERP_KERNEL::Exception(oss.str().c_str());
7131             }
7132         }
7133       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
7134         (*it).second->decrRef();
7135     }
7136 }
7137
7138 /*!
7139  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
7140  * 
7141  */
7142 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
7143                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
7144                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
7145                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2,
7146                                                    std::vector<double>& addCoo) throw(INTERP_KERNEL::Exception)
7147 {
7148   static const int SPACEDIM=2;
7149   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
7150   desc2=DataArrayInt::New();
7151   descIndx2=DataArrayInt::New();
7152   revDesc2=DataArrayInt::New();
7153   revDescIndx2=DataArrayInt::New();
7154   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
7155   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
7156   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
7157   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
7158   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
7159   const int *c1=m1Desc->getNodalConnectivity()->getConstPointer();
7160   const int *ci1=m1Desc->getNodalConnectivityIndex()->getConstPointer();
7161   std::vector<double> bbox1,bbox2;
7162   m1Desc->getBoundingBoxForBBTree(bbox1);
7163   m2Desc->getBoundingBoxForBBTree(bbox2);
7164   int ncell1=m1Desc->getNumberOfCells();
7165   int ncell2=m2Desc->getNumberOfCells();
7166   intersectEdge1.resize(ncell1);
7167   colinear2.resize(ncell2);
7168   subDiv2.resize(ncell2);
7169   BBTree<SPACEDIM,int> myTree(&bbox2[0],0,0,m2Desc->getNumberOfCells(),-eps);
7170   std::vector<int> candidates1(1);
7171   int offset1=m1->getNumberOfNodes();
7172   int offset2=offset1+m2->getNumberOfNodes();
7173   for(int i=0;i<ncell1;i++)
7174     {
7175       std::vector<int> candidates2;
7176       myTree.getIntersectingElems(&bbox1[i*2*SPACEDIM],candidates2);
7177       if(!candidates2.empty())
7178         {
7179           std::map<INTERP_KERNEL::Node *,int> map1,map2;
7180           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
7181           candidates1[0]=i;
7182           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
7183           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo);
7184           delete pol2;
7185           delete pol1;
7186         }
7187       else
7188         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i+1]);
7189     }
7190   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
7191   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
7192 }
7193
7194 /*!
7195  * This method performs the 2nd step of Partition of 2D mesh.
7196  * This method has 4 inputs :
7197  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
7198  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
7199  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids in randomly sorted.
7200  * The aim of this method is to sort the splitting nodes, if any, and to put in 'intersectEdge' output paramter based on edges of mesh 'm2'
7201  * @param m1 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method. Only present for its coords in case of 'subDiv' shares some nodes of 'm1'
7202  * @param m2 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
7203  * @param addCoo input parameter with additionnal nodes linked to intersection of the 2 meshes.
7204  */
7205 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, const std::vector<double>& addCoo, const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge) throw(INTERP_KERNEL::Exception)
7206 {
7207   int offset1=m1->getNumberOfNodes();
7208   int ncell=m2->getNumberOfCells();
7209   const int *c=m2->getNodalConnectivity()->getConstPointer();
7210   const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
7211   const double *coo=m2->getCoords()->getConstPointer();
7212   const double *cooBis=m1->getCoords()->getConstPointer();
7213   int offset2=offset1+m2->getNumberOfNodes();
7214   intersectEdge.resize(ncell);
7215   for(int i=0;i<ncell;i++,cI++)
7216     {
7217       const std::vector<int>& divs=subDiv[i];
7218       int nnode=cI[1]-cI[0]-1;
7219       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
7220       std::map<INTERP_KERNEL::Node *, int> mapp22;
7221       for(int j=0;j<nnode;j++)
7222         {
7223           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
7224           int nnid=c[(*cI)+j+1];
7225           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
7226           mapp22[nn]=nnid+offset1;
7227         }
7228       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
7229       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
7230         ((*it).second.first)->decrRef();
7231       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
7232       std::map<INTERP_KERNEL::Node *,int> mapp3;
7233       for(std::size_t j=0;j<divs.size();j++)
7234         {
7235           int id=divs[j];
7236           INTERP_KERNEL::Node *tmp=0;
7237           if(id<offset1)
7238             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
7239           else if(id<offset2)
7240             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
7241           else
7242             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
7243           addNodes[j]=tmp;
7244           mapp3[tmp]=id;
7245         }
7246       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
7247       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
7248         (*it)->decrRef();
7249       e->decrRef();
7250     }
7251 }
7252
7253 /*!
7254  * This method is part of the Slice3D algorithm. It is the first step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
7255  * This method allows to compute given the status of 3D curve cells and the descending connectivity 3DSurf->3DCurve to deduce the intersection of each 3D surf cells
7256  * with a plane. The result will be put in 'cut3DSuf' out parameter.
7257  * @param cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
7258  * @param nodesOnPlane, returns all the nodes that are on the plane.
7259  * @param nodal3DSurf is the nodal connectivity of 3D surf mesh.
7260  * @param nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
7261  * @param nodal3DCurve is the nodal connectivity of 3D curve mesh.
7262  * @param nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
7263  * @param desc is the descending connectivity 3DSurf->3DCurve
7264  * @param descIndx is the descending connectivity index 3DSurf->3DCurve
7265  * @param cut3DSuf input/output param.
7266  */
7267 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
7268                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
7269                                                    const int *desc, const int *descIndx, 
7270                                                    std::vector< std::pair<int,int> >& cut3DSurf) throw(INTERP_KERNEL::Exception)
7271 {
7272   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
7273   int nbOf3DSurfCell=(int)cut3DSurf.size();
7274   for(int i=0;i<nbOf3DSurfCell;i++)
7275     {
7276       std::vector<int> res;
7277       int offset=descIndx[i];
7278       int nbOfSeg=descIndx[i+1]-offset;
7279       for(int j=0;j<nbOfSeg;j++)
7280         {
7281           int edgeId=desc[offset+j];
7282           int status=cut3DCurve[edgeId];
7283           if(status!=-2)
7284             {
7285               if(status>-1)
7286                 res.push_back(status);
7287               else
7288                 {
7289                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
7290                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
7291                 }
7292             }
7293         }
7294       switch(res.size())
7295         {
7296         case 2:
7297           {
7298             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
7299             break;
7300           }
7301         case 1:
7302         case 0:
7303           {
7304             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
7305             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
7306             if(res.size()==2)
7307               {
7308                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
7309               }
7310             else
7311               {
7312                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
7313               }
7314             break;
7315           }
7316         default:
7317           {// case when plane is on a multi colinear edge of a polyhedron
7318             if((int)res.size()==2*nbOfSeg)
7319               {
7320                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
7321               }
7322             else
7323               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
7324           }
7325         }
7326     }
7327 }
7328
7329 /*!
7330  * 'this' is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
7331  * This method is part of the Slice3D algorithm. It is the second step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
7332  * This method allows to compute given the result of 3D surf cells with plane and the descending connectivity 3D->3DSurf to deduce the intersection of each 3D cells
7333  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
7334  * @param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
7335  * @param desc is the descending connectivity 3D->3DSurf
7336  * @param descIndx is the descending connectivity index 3D->3DSurf
7337  */
7338 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
7339                                                   const int *desc, const int *descIndx,
7340                                                   DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const throw(INTERP_KERNEL::Exception)
7341 {
7342   checkFullyDefined();
7343   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7344     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
7345   const int *nodal3D=_nodal_connec->getConstPointer();
7346   const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
7347   int nbOfCells=getNumberOfCells();
7348   for(int i=0;i<nbOfCells;i++)
7349     {
7350       std::map<int, std::set<int> > m;
7351       int offset=descIndx[i];
7352       int nbOfFaces=descIndx[i+1]-offset;
7353       int start=-1;
7354       int end=-1;
7355       for(int j=0;j<nbOfFaces;j++)
7356         {
7357           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
7358           if(p.first!=-1 && p.second!=-1)
7359             {
7360               if(p.first!=-2)
7361                 {
7362                   start=p.first; end=p.second;
7363                   m[p.first].insert(p.second);
7364                   m[p.second].insert(p.first);
7365                 }
7366               else
7367                 {
7368                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
7369                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
7370                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
7371                   INTERP_KERNEL::NormalizedCellType cmsId;
7372                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
7373                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
7374                   for(unsigned k=0;k<nbOfNodesSon;k++)
7375                     {
7376                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
7377                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
7378                     }
7379                 }
7380             }
7381         }
7382       if(m.empty())
7383         continue;
7384       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
7385       int prev=end;
7386       while(end!=start)
7387         {
7388           std::map<int, std::set<int> >::const_iterator it=m.find(start);
7389           const std::set<int>& s=(*it).second;
7390           std::set<int> s2; s2.insert(prev);
7391           std::set<int> s3;
7392           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
7393           if(s3.size()==1)
7394             {
7395               int val=*s3.begin();
7396               conn.push_back(start);
7397               prev=start;
7398               start=val;
7399             }
7400           else
7401             start=end;
7402         }
7403       conn.push_back(end);
7404       if(conn.size()>3)
7405         {
7406           nodalRes->insertAtTheEnd(conn.begin(),conn.end());
7407           nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
7408           cellIds->pushBackSilent(i);
7409         }
7410     }
7411 }
7412
7413 /*!
7414  * This method compute the convex hull of a single 2D cell. This method tries to conserve at maximum the given input connectivity. In particular, if the orientation of cell is not clockwise
7415  * as in MED format norm. If definitely the result of Jarvis algorithm is not matchable with the input connectivity, the result will be copied into \b nodalConnecOut parameter and
7416  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7417  * This method excepts that \b coords parameter is expected to be in dimension 2. [\b nodalConnBg, \b nodalConnEnd) is the nodal connectivity of the input
7418  * cell (geometric cell type included at the position 0). If the meshdimension of the input cell is not equal to 2 an INTERP_KERNEL::Exception will be thrown.
7419  * 
7420  * @return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7421  */
7422 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut) throw(INTERP_KERNEL::Exception)
7423 {
7424   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7425   if(sz>=4)
7426     {
7427       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7428       if(cm.getDimension()==2)
7429         {
7430           const int *node=nodalConnBg+1;
7431           int startNode=*node++;
7432           double refX=coords[2*startNode];
7433           for(;node!=nodalConnEnd;node++)
7434             {
7435               if(coords[2*(*node)]<refX)
7436                 {
7437                   startNode=*node;
7438                   refX=coords[2*startNode];
7439                 }
7440             }
7441           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7442           refX=1e300;
7443           double tmp1;
7444           double tmp2[2];
7445           double angle0=-M_PI/2;
7446           //
7447           int nextNode=-1;
7448           int prevNode=-1;
7449           double resRef;
7450           double angleNext;
7451           while(nextNode!=startNode)
7452             {
7453               nextNode=-1;
7454               resRef=1e300;
7455               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7456                 {
7457                   if(*node!=tmpOut.back() && *node!=prevNode)
7458                     {
7459                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7460                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7461                       double res;
7462                       if(angleM<=angle0)
7463                         res=angle0-angleM;
7464                       else
7465                         res=angle0-angleM+2.*M_PI;
7466                       if(res<resRef)
7467                         {
7468                           nextNode=*node;
7469                           resRef=res;
7470                           angleNext=angleM;
7471                         }
7472                     }
7473                 }
7474               if(nextNode!=startNode)
7475                 {
7476                   angle0=angleNext-M_PI;
7477                   if(angle0<-M_PI)
7478                     angle0+=2*M_PI;
7479                   prevNode=tmpOut.back();
7480                   tmpOut.push_back(nextNode);
7481                 }
7482             }
7483           std::vector<int> tmp3(2*(sz-1));
7484           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7485           std::copy(nodalConnBg+1,nodalConnEnd,it);
7486           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7487             {
7488               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7489               return false;
7490             }
7491           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7492             {
7493               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7494               return false;
7495             }
7496           else
7497             {
7498               nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
7499               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7500               return true;
7501             }
7502         }
7503       else
7504         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7505     }
7506   else
7507     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7508 }
7509
7510 /*!
7511  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7512  * This method will not impact the size of inout parameter \b arrIndx but the size of \b arr will be modified in case of suppression.
7513  * 
7514  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7515  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7516  * \param [in,out] arr array in which the remove operation will be done.
7517  * \param [in,out] arrIndx array in the remove operation will modify
7518  * \param [in] offsetForRemoval (by default 0) offset so that for each i in [0,arrIndx->getNumberOfTuples()-1) removal process will be performed in the following range [arr+arrIndx[i]+offsetForRemoval,arr+arr[i+1])
7519  * \return true if \b arr and \b arrIndx have been modified, false if not.
7520  */
7521 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval) throw(INTERP_KERNEL::Exception)
7522 {
7523   if(!arrIndx || !arr)
7524     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7525   if(offsetForRemoval<0)
7526     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7527   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7528   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7529   int *arrIPtr=arrIndx->getPointer();
7530   *arrIPtr++=0;
7531   int previousArrI=0;
7532   const int *arrPtr=arr->getConstPointer();
7533   std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
7534   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7535     {
7536       if(*arrIPtr-previousArrI>offsetForRemoval)
7537         {
7538           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7539             {
7540               if(s.find(*work)==s.end())
7541                 arrOut.push_back(*work);
7542             }
7543         }
7544       previousArrI=*arrIPtr;
7545       *arrIPtr=(int)arrOut.size();
7546     }
7547   if(arr->getNumberOfTuples()==(int)arrOut.size())
7548     return false;
7549   arr->alloc((int)arrOut.size(),1);
7550   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7551   return true;
7552 }
7553
7554 /*!
7555  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7556  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7557  * The selection of extraction is done standardly in new2old format.
7558  * This method returns indexed arrays using 2 arrays (arrOut,arrIndexOut).
7559  *
7560  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7561  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7562  * \param [in] arrIn arr origin array from which the extraction will be done.
7563  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7564  * \param [out] arrOut the resulting array
7565  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7566  */
7567 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7568                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7569 {
7570   if(!arrIn || !arrIndxIn)
7571     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7572   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7573   const int *arrInPtr=arrIn->getConstPointer();
7574   const int *arrIndxPtr=arrIndxIn->getConstPointer();
7575   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7576   int maxSizeOfArr=arrIn->getNumberOfTuples();
7577   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7578   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7579   arrIo->alloc((int)(sz+1),1);
7580   const int *idsIt=idsOfSelectBg;
7581   int *work=arrIo->getPointer();
7582   *work++=0;
7583   int lgth=0;
7584   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7585     {
7586       if(*idsIt>=0 && *idsIt<nbOfGrps)
7587         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7588       else
7589         {
7590           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7591           throw INTERP_KERNEL::Exception(oss.str().c_str());
7592         }
7593       if(lgth>=work[-1])
7594         *work=lgth;
7595       else
7596         {
7597           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7598           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7599           throw INTERP_KERNEL::Exception(oss.str().c_str());
7600         }
7601     }
7602   arro->alloc(lgth,1);
7603   work=arro->getPointer();
7604   idsIt=idsOfSelectBg;
7605   for(std::size_t i=0;i<sz;i++,idsIt++)
7606     {
7607       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7608         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7609       else
7610         {
7611           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7612           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7613           throw INTERP_KERNEL::Exception(oss.str().c_str());
7614         }
7615     }
7616   arrOut=arro.retn();
7617   arrIndexOut=arrIo.retn();
7618 }
7619
7620 /*!
7621  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7622  * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [\b idsOfSelectBg, \b idsOfSelectEnd) and for
7623  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7624  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7625  *
7626  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7627  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7628  * \param [in] arrIn arr origin array from which the extraction will be done.
7629  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7630  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7631  * \param [in] srcArrIndex index array of \b srcArr
7632  * \param [out] arrOut the resulting array
7633  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7634  * 
7635  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7636  */
7637 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7638                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7639                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7640 {
7641   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7642     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7643   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7644   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7645   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7646   std::vector<bool> v(nbOfTuples,true);
7647   int offset=0;
7648   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7649   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7650   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7651     {
7652       if(*it>=0 && *it<nbOfTuples)
7653         {
7654           v[*it]=false;
7655           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7656         }
7657       else
7658         {
7659           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7660           throw INTERP_KERNEL::Exception(oss.str().c_str());
7661         }
7662     }
7663   srcArrIndexPtr=srcArrIndex->getConstPointer();
7664   arrIo->alloc(nbOfTuples+1,1);
7665   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7666   const int *arrInPtr=arrIn->getConstPointer();
7667   const int *srcArrPtr=srcArr->getConstPointer();
7668   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7669   int *arroPtr=arro->getPointer();
7670   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7671     {
7672       if(v[ii])
7673         {
7674           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7675           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7676         }
7677       else
7678         {
7679           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7680           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7681           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7682         }
7683     }
7684   arrOut=arro.retn();
7685   arrIndexOut=arrIo.retn();
7686 }
7687
7688 /*!
7689  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7690  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7691  *
7692  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7693  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7694  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7695  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7696  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7697  * \param [in] srcArrIndex index array of \b srcArr
7698  * 
7699  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7700  */
7701 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7702                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex) throw(INTERP_KERNEL::Exception)
7703 {
7704   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7705     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7706   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7707   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7708   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7709   int *arrInOutPtr=arrInOut->getPointer();
7710   const int *srcArrPtr=srcArr->getConstPointer();
7711   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7712     {
7713       if(*it>=0 && *it<nbOfTuples)
7714         {
7715           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7716             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7717           else
7718             {
7719               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " id (idsOfSelectBg[" << std::distance(idsOfSelectBg,it)<< "]) is " << *it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
7720               throw INTERP_KERNEL::Exception(oss.str().c_str());
7721             }
7722         }
7723       else
7724         {
7725           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7726           throw INTERP_KERNEL::Exception(oss.str().c_str());
7727         }
7728     }
7729 }
7730
7731 /*!
7732  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7733  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7734  * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
7735  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7736  * A negative value in \b arrIn means that it is ignored.
7737  * This method is usefull to see if a mesh is contiguous regarding its connectivity. If it is not the case the size of returned array is different from arrIndxIn->getNumberOfTuples()-1.
7738  * 
7739  * \param [in] arrIn arr origin array from which the extraction will be done.
7740  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7741  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7742  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7743  */
7744 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn) throw(INTERP_KERNEL::Exception)
7745 {
7746   int seed=0,nbOfDepthPeelingPerformed=0;
7747   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7748 }
7749
7750 /*!
7751  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7752  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7753  * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
7754  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7755  * A negative value in \b arrIn means that it is ignored.
7756  * This method is usefull to see if a mesh is contiguous regarding its connectivity. If it is not the case the size of returned array is different from arrIndxIn->getNumberOfTuples()-1.
7757  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7758  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7759  * \param [in] arrIn arr origin array from which the extraction will be done.
7760  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7761  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7762  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7763  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7764  * \sa MEDCouplingUMesh::partitionBySpreadZone
7765  */
7766 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed) throw(INTERP_KERNEL::Exception)
7767 {
7768   nbOfDepthPeelingPerformed=0;
7769   if(!arrIndxIn)
7770     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7771   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7772   if(nbOfTuples<=0)
7773     {
7774       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
7775       return ret;
7776     }
7777   //
7778   std::vector<bool> fetched(nbOfTuples,false);
7779   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7780 }
7781
7782 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed) throw(INTERP_KERNEL::Exception)
7783 {
7784   nbOfDepthPeelingPerformed=0;
7785   if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
7786     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
7787   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7788   std::vector<bool> fetched2(nbOfTuples,false);
7789   int i=0;
7790   for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
7791     {
7792       if(*seedElt>=0 && *seedElt<nbOfTuples)
7793         { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
7794       else
7795         { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
7796     }
7797   const int *arrInPtr=arrIn->getConstPointer();
7798   const int *arrIndxPtr=arrIndxIn->getConstPointer();
7799   int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
7800   std::vector<int> idsToFetch1(seedBg,seedEnd);
7801   std::vector<int> idsToFetch2;
7802   std::vector<int> *idsToFetch=&idsToFetch1;
7803   std::vector<int> *idsToFetchOther=&idsToFetch2;
7804   while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
7805     {
7806       for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
7807         for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
7808           if(!fetched[*it2])
7809             { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
7810       std::swap(idsToFetch,idsToFetchOther);
7811       idsToFetchOther->clear();
7812       nbOfDepthPeelingPerformed++;
7813     }
7814   int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
7815   i=0;
7816   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
7817   int *retPtr=ret->getPointer();
7818   for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
7819     if(*it)
7820       *retPtr++=i;
7821   return ret.retn();
7822 }
7823
7824 /*!
7825  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7826  * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [\b idsOfSelectBg, \b idsOfSelectEnd) and for
7827  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7828  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7829  *
7830  * \param [in] start begin of set of ids of the input extraction (included)
7831  * \param [in] end end of set of ids of the input extraction (excluded)
7832  * \param [in] step step of the set of ids in range mode.
7833  * \param [in] arrIn arr origin array from which the extraction will be done.
7834  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7835  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7836  * \param [in] srcArrIndex index array of \b srcArr
7837  * \param [out] arrOut the resulting array
7838  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7839  * 
7840  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
7841  */
7842 void MEDCouplingUMesh::SetPartOfIndexedArrays2(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7843                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7844                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7845 {
7846   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7847     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays2 : presence of null pointer in input parameter !");
7848   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7849   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7850   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7851   int offset=0;
7852   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7853   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7854   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArrays2 : ");
7855   int it=start;
7856   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7857     {
7858       if(it>=0 && it<nbOfTuples)
7859         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
7860       else
7861         {
7862           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays2 : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
7863           throw INTERP_KERNEL::Exception(oss.str().c_str());
7864         }
7865     }
7866   srcArrIndexPtr=srcArrIndex->getConstPointer();
7867   arrIo->alloc(nbOfTuples+1,1);
7868   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7869   const int *arrInPtr=arrIn->getConstPointer();
7870   const int *srcArrPtr=srcArr->getConstPointer();
7871   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7872   int *arroPtr=arro->getPointer();
7873   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7874     {
7875       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
7876       if(pos<0)
7877         {
7878           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7879           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7880         }
7881       else
7882         {
7883           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7884           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7885         }
7886     }
7887   arrOut=arro.retn();
7888   arrIndexOut=arrIo.retn();
7889 }
7890
7891 /*!
7892  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7893  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7894  *
7895  * \param [in] start begin of set of ids of the input extraction (included)
7896  * \param [in] end end of set of ids of the input extraction (excluded)
7897  * \param [in] step step of the set of ids in range mode.
7898  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7899  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7900  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7901  * \param [in] srcArrIndex index array of \b srcArr
7902  * 
7903  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays2 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7904  */
7905 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7906                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex) throw(INTERP_KERNEL::Exception)
7907 {
7908   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7909     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : presence of null pointer in input parameter !");
7910   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7911   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7912   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7913   int *arrInOutPtr=arrInOut->getPointer();
7914   const int *srcArrPtr=srcArr->getConstPointer();
7915   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : ");
7916   int it=start;
7917   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7918     {
7919       if(it>=0 && it<nbOfTuples)
7920         {
7921           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
7922             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
7923           else
7924             {
7925               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
7926               throw INTERP_KERNEL::Exception(oss.str().c_str());
7927             }
7928         }
7929       else
7930         {
7931           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
7932           throw INTERP_KERNEL::Exception(oss.str().c_str());
7933         }
7934     }
7935 }
7936
7937 /*!
7938  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7939  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7940  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7941  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7942  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7943  * 
7944  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7945  */
7946 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const throw(INTERP_KERNEL::Exception)
7947 {
7948   checkFullyDefined();
7949   int mdim=getMeshDimension();
7950   int spaceDim=getSpaceDimension();
7951   if(mdim!=spaceDim)
7952     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7953   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
7954   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
7955   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > >(partitionAuto));
7956   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7957   ret->setCoords(getCoords());
7958   ret->allocateCells((int)partition.size());
7959   //
7960   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
7961     {
7962       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7963       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cell;
7964       switch(mdim)
7965         {
7966         case 2:
7967           cell=tmp->buildUnionOf2DMesh();
7968           break;
7969         case 3:
7970           cell=tmp->buildUnionOf3DMesh();
7971           break;
7972         default:
7973           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7974         }
7975       
7976       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
7977     }
7978   //
7979   ret->finishInsertingCells();
7980   return ret.retn();
7981 }
7982
7983 /*!
7984  * This method partitions \b this into contiguous zone.
7985  * This method only needs a well defined connectivity. Coordinates are not considered here.
7986  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7987  */
7988 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const throw(INTERP_KERNEL::Exception)
7989 {
7990   //#if 0
7991   int nbOfCellsCur=getNumberOfCells();
7992   std::vector<DataArrayInt *> ret;
7993   if(nbOfCellsCur<=0)
7994     return ret;
7995   DataArrayInt *neigh=0,*neighI=0;
7996   computeNeighborsOfCells(neigh,neighI);
7997   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
7998   std::vector<bool> fetchedCells(nbOfCellsCur,false);
7999   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > ret2;
8000   int seed=0;
8001   while(seed<nbOfCellsCur)
8002     {
8003       int nbOfPeelPerformed=0;
8004       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
8005       seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
8006     }
8007   for(std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
8008     ret.push_back((*it).retn());
8009   return ret;
8010   //#endif
8011 #if 0
8012   int nbOfCellsCur=getNumberOfCells();
8013   DataArrayInt *neigh=0,*neighI=0;
8014   computeNeighborsOfCells(neigh,neighI);
8015   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
8016   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids=DataArrayInt::New(); ids->alloc(nbOfCellsCur,1); ids->iota();
8017   std::vector<DataArrayInt *> ret;
8018   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > ret2;
8019   while(nbOfCellsCur>0)
8020     {
8021       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=MEDCouplingUMesh::ComputeSpreadZoneGradually(neighAuto,neighIAuto);
8022       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp3=tmp->buildComplement(nbOfCellsCur);
8023       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp2=ids->selectByTupleId(tmp->begin(),tmp->end());
8024       ret2.push_back(tmp2);  ret.push_back(tmp2);
8025       nbOfCellsCur=tmp3->getNumberOfTuples();
8026       if(nbOfCellsCur>0)
8027         {
8028           ids=ids->selectByTupleId(tmp3->begin(),tmp3->end());
8029           MEDCouplingUMesh::ExtractFromIndexedArrays(tmp3->begin(),tmp3->end(),neighAuto,neighIAuto,neigh,neighI);
8030           neighAuto=neigh;
8031           neighIAuto=neighI;
8032           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renum=tmp3->invertArrayN2O2O2N(nbOfCellsCur+tmp->getNumberOfTuples());
8033           neighAuto->transformWithIndArr(renum->begin(),renum->end());
8034         }
8035     }
8036   for(std::vector<DataArrayInt *>::const_iterator it=ret.begin();it!=ret.end();it++)
8037     (*it)->incrRef();
8038   return ret;
8039 #endif
8040 }
8041
8042 /*!
8043  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8044  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
8045  *
8046  * \param [in] code a code with the same format than those returned by MEDCouplingUMesh::getDistributionOfTypes except for the code[3*k+2] that should contain start id of chunck.
8047  * \return a newly allocated DataArrayInt to be managed by the caller.
8048  * \throw In case of \a code has not the right format (typically of size 3*n)
8049  */
8050 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code) throw(INTERP_KERNEL::Exception)
8051 {
8052   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
8053   std::size_t nb=code.size()/3;
8054   if(code.size()%3!=0)
8055     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8056   ret->alloc((int)nb,2);
8057   int *retPtr=ret->getPointer();
8058   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8059     {
8060       retPtr[0]=code[3*i+2];
8061       retPtr[1]=code[3*i+2]+code[3*i+1];
8062     }
8063   return ret.retn();
8064 }
8065
8066 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8067                                                                                    _own_cell(true),_cell_id(-1),_nb_cell(0)
8068 {
8069   if(mesh)
8070     {
8071       mesh->incrRef();
8072       _nb_cell=mesh->getNumberOfCells();
8073     }
8074 }
8075
8076 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8077 {
8078   if(_mesh)
8079     _mesh->decrRef();
8080   if(_own_cell)
8081     delete _cell;
8082 }
8083
8084 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
8085                                                                                                                                _own_cell(false),_cell_id(bg-1),
8086                                                                                                                                _nb_cell(end)
8087 {
8088   if(mesh)
8089     mesh->incrRef();
8090 }
8091
8092 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8093 {
8094   _cell_id++;
8095   if(_cell_id<_nb_cell)
8096     {
8097       _cell->next();
8098       return _cell;
8099     }
8100   else
8101     return 0;
8102 }
8103
8104 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8105 {
8106   if(_mesh)
8107     _mesh->incrRef();
8108 }
8109
8110 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8111 {
8112   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8113 }
8114
8115 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8116 {
8117   if(_mesh)
8118     _mesh->decrRef();
8119 }
8120
8121 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
8122                                                                                                                                                                   _itc(itc),
8123                                                                                                                                                                   _bg(bg),_end(end)
8124 {
8125   if(_mesh)
8126     _mesh->incrRef();
8127 }
8128
8129 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8130 {
8131   if(_mesh)
8132     _mesh->decrRef();
8133 }
8134
8135 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8136 {
8137   return _type;
8138 }
8139
8140 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
8141 {
8142   return _end-_bg;
8143 }
8144
8145 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8146 {
8147   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8148 }
8149
8150 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8151 {
8152   if(mesh)
8153     {
8154       mesh->incrRef();
8155       _nb_cell=mesh->getNumberOfCells();
8156     }
8157 }
8158
8159 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8160 {
8161   if(_mesh)
8162     _mesh->decrRef();
8163   delete _cell;
8164 }
8165
8166 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8167 {
8168   const int *c=_mesh->getNodalConnectivity()->getConstPointer();
8169   const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
8170   if(_cell_id<_nb_cell)
8171     {
8172       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8173       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,ParaMEDMEMImpl::ConnReader(c,type)));
8174       int startId=_cell_id;
8175       _cell_id+=nbOfElems;
8176       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8177     }
8178   else
8179     return 0;
8180 }
8181
8182 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8183 {
8184   if(mesh)
8185     {
8186       _conn=mesh->getNodalConnectivity()->getPointer();
8187       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8188     }
8189 }
8190
8191 void MEDCouplingUMeshCell::next()
8192 {
8193   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8194     {
8195       _conn+=_conn_lgth;
8196       _conn_indx++;
8197     }
8198   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8199 }
8200
8201 std::string MEDCouplingUMeshCell::repr() const
8202 {
8203   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8204     {
8205       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8206       oss << " : ";
8207       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
8208       return oss.str();
8209     }
8210   else
8211     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8212 }
8213
8214 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8215 {
8216   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8217     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8218   else
8219     return INTERP_KERNEL::NORM_ERROR;
8220 }
8221
8222 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
8223 {
8224   lgth=_conn_lgth;
8225   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8226     return _conn;
8227   else
8228     return 0;
8229 }