Salome HOME
1) Add CMake files to the dist rules (make dist)
[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 "DirectedBoundingBox.hxx"
30 #include "InterpKernelMeshQuality.hxx"
31 #include "InterpKernelCellSimplify.hxx"
32 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
33 #include "MEDCouplingAutoRefCountObjectPtr.hxx"
34 #include "InterpKernelAutoPtr.hxx"
35 #include "InterpKernelGeo2DNode.hxx"
36 #include "InterpKernelGeo2DEdgeLin.hxx"
37 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
38 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
39
40 #include <sstream>
41 #include <fstream>
42 #include <numeric>
43 #include <cstring>
44 #include <limits>
45 #include <list>
46
47 using namespace ParaMEDMEM;
48
49 const char MEDCouplingUMesh::PART_OF_NAME[]="PartOf_";
50
51 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
52
53 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 };
54
55 MEDCouplingUMesh *MEDCouplingUMesh::New()
56 {
57   return new MEDCouplingUMesh;
58 }
59
60 MEDCouplingUMesh *MEDCouplingUMesh::New(const char *meshName, int meshDim)
61 {
62   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
63   ret->setName(meshName);
64   ret->setMeshDimension(meshDim);
65   return ret;
66 }
67
68 MEDCouplingMesh *MEDCouplingUMesh::deepCpy() const
69 {
70   return clone(true);
71 }
72
73 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
74 {
75   return new MEDCouplingUMesh(*this,recDeepCpy);
76 }
77
78 void MEDCouplingUMesh::updateTime() const
79 {
80   MEDCouplingPointSet::updateTime();
81   if(_nodal_connec)
82     {
83       updateTimeWith(*_nodal_connec);
84     }
85   if(_nodal_connec_index)
86     {
87       updateTimeWith(*_nodal_connec_index);
88     }
89 }
90
91 MEDCouplingUMesh::MEDCouplingUMesh():_iterator(-1),_mesh_dim(-2),
92                                      _nodal_connec(0),_nodal_connec_index(0)
93 {
94 }
95
96 /*!
97  * This method checks that this is correctly designed. For example le coordinates are set, nodal connectivity.
98  * When this method returns without throwing any exception, 'this' is expected to be writable, exchangeable and to be 
99  * available for most of algorithm. When a mesh has been constructed from scratch it is a good habits to call this method to check
100  * that all is in order in 'this'.
101  */
102 void MEDCouplingUMesh::checkCoherency() const throw(INTERP_KERNEL::Exception)
103 {
104   if(_mesh_dim<-1)
105     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
106   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
107     {
108       if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
109         {
110           std::ostringstream message;
111           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
112           throw INTERP_KERNEL::Exception(message.str().c_str());
113         }
114     }
115   if(_nodal_connec)
116     {
117       if(_nodal_connec->getNumberOfComponents()!=1)
118         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
119       if(_nodal_connec->getInfoOnComponent(0)!="")
120         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
121     }
122   if(_nodal_connec_index)
123     {
124       if(_nodal_connec_index->getNumberOfComponents()!=1)
125         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
126       if(_nodal_connec_index->getInfoOnComponent(0)!="")
127         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
128     }
129   if(_iterator!=-1)
130     {
131       throw INTERP_KERNEL::Exception("It appears that finishInsertingCells method has not been invoked after a insertNextCell session !");
132     }
133 }
134
135 /*!
136  * This method performs deeper checking in 'this' than MEDCouplingUMesh::checkCoherency does.
137  * So this method is more time-consuming. This method checks that nodal connectivity points to valid node ids.
138  * No geometrical aspects are checked here. These aspects are done in MEDCouplingUMesh::checkCoherency2.
139  */
140 void MEDCouplingUMesh::checkCoherency1(double eps) const throw(INTERP_KERNEL::Exception)
141 {
142   checkCoherency();
143   if(_mesh_dim==-1)
144     return ;
145   int meshDim=getMeshDimension();
146   int nbOfNodes=getNumberOfNodes();
147   int nbOfCells=getNumberOfCells();
148   const int *ptr=_nodal_connec->getConstPointer();
149   const int *ptrI=_nodal_connec_index->getConstPointer();
150   for(int i=0;i<nbOfCells;i++)
151     {
152       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
153       if((int)cm.getDimension()!=meshDim)
154         {
155           std::ostringstream oss;
156           oss << "MEDCouplingUMesh::checkCoherency1 : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
157           throw INTERP_KERNEL::Exception(oss.str().c_str());
158         }
159       int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
160       if(!cm.isDynamic())
161         if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
162           {
163             std::ostringstream oss;
164             oss << "MEDCouplingUMesh::checkCoherency1 : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
165             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
166             throw INTERP_KERNEL::Exception(oss.str().c_str());
167           }
168       for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
169         {
170           int nodeId=*w;
171           if(nodeId>=0)
172             {
173               if(nodeId>=nbOfNodes)
174                 {
175                   std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes !";
176                   throw INTERP_KERNEL::Exception(oss.str().c_str());
177                 }
178             }
179           else if(nodeId<-1)
180             {
181               std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #" << nodeId << " in connectivity ! sounds bad !";
182               throw INTERP_KERNEL::Exception(oss.str().c_str());
183             }
184           else
185             {
186               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
187                 {
188                   std::ostringstream oss; oss << "Cell #" << i << " is consituted of node #-1 in connectivity ! sounds bad !";
189                   throw INTERP_KERNEL::Exception(oss.str().c_str());
190                 }
191             }
192         }
193     }
194 }
195
196 void MEDCouplingUMesh::checkCoherency2(double eps) const throw(INTERP_KERNEL::Exception)
197 {
198   checkCoherency1(eps);
199 }
200
201 void MEDCouplingUMesh::setMeshDimension(int meshDim)
202 {
203   if(meshDim<-1)
204     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 !");
205   _mesh_dim=meshDim;
206   declareAsNew();
207 }
208
209 void MEDCouplingUMesh::allocateCells(int nbOfCells)
210 {
211   if(_nodal_connec_index)
212     {
213       _nodal_connec_index->decrRef();
214     }
215   if(_nodal_connec)
216     {
217       _nodal_connec->decrRef();
218     }
219
220   _nodal_connec_index=DataArrayInt::New();
221   _nodal_connec_index->alloc(nbOfCells+1,1);
222   int *pt=_nodal_connec_index->getPointer();
223   pt[0]=0;
224   _nodal_connec=DataArrayInt::New();
225   _nodal_connec->alloc(2*nbOfCells,1);
226   _iterator=0;
227   _types.clear();
228   declareAsNew();
229 }
230
231 /*!
232  * Appends a cell in connectivity array.
233  * @param type type of cell to add.
234  * @param size number of nodes constituting this cell.
235  * @param nodalConnOfCell the connectivity of the cell to add.
236  */
237 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell) throw(INTERP_KERNEL::Exception)
238 {
239   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
240   if(_nodal_connec_index==0)
241     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
242   if((int)cm.getDimension()==_mesh_dim)
243     {
244       int nbOfElems=_nodal_connec_index->getNbOfElems()-1;
245       if(_iterator>=nbOfElems)
246         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : allocation of cells was wide enough ! Call insertNextCell with higher value or call finishInsertingCells !");
247       int *pt=_nodal_connec_index->getPointer();
248       int idx=pt[_iterator];
249       
250       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
251       _types.insert(type);
252       pt[++_iterator]=idx+size+1;
253     }
254   else
255     {
256       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
257       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
258       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
259       throw INTERP_KERNEL::Exception(oss.str().c_str());
260     }
261 }
262
263 /*!
264  * Method to be called to cloture the insertion of cells using this->insertNextCell.
265  */
266 void MEDCouplingUMesh::finishInsertingCells()
267 {
268   const int *pt=_nodal_connec_index->getConstPointer();
269   int idx=pt[_iterator];
270
271   _nodal_connec->reAlloc(idx);
272   _nodal_connec_index->reAlloc(_iterator+1);
273   _iterator=-1;
274   _nodal_connec->declareAsNew();
275   _nodal_connec_index->declareAsNew();
276   updateTime();
277 }
278
279 /*!
280  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
281  * Useful for python users.
282  */
283 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
284 {
285   return new MEDCouplingUMeshCellIterator(this);
286 }
287
288 /*!
289  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
290  * If 'this' is not so that that cells are grouped by geo types this method will throw an exception.
291  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
292  * Useful for python users.
293  */
294 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType() throw(INTERP_KERNEL::Exception)
295 {
296   if(!checkConsecutiveCellTypes())
297     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
298   return new MEDCouplingUMeshCellByTypeEntry(this);
299 }
300
301 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
302 {
303   return _types;
304 }
305
306 /*!
307  * This method is a method that compares 'this' and 'other'.
308  * This method compares \b all attributes, even names and component names.
309  */
310 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const throw(INTERP_KERNEL::Exception)
311 {
312   if(!other)
313     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
314   std::ostringstream oss; oss.precision(15);
315   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
316   if(!otherC)
317     {
318       reason="mesh given in input is not castable in MEDCouplingUMesh !";
319       return false;
320     }
321   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
322     return false;
323   if(_mesh_dim!=otherC->_mesh_dim)
324     {
325       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
326       reason=oss.str();
327       return false;
328     }
329   if(_types!=otherC->_types)
330     {
331       oss << "umesh geometric type mismatch :\nThis geometric types are :";
332       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
333         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
334       oss << "\nOther geometric types are :";
335       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
336         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
337       reason=oss.str();
338       return false;
339     }
340   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
341     if(_nodal_connec==0 || otherC->_nodal_connec==0)
342       {
343         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
344         return false;
345       }
346   if(_nodal_connec!=otherC->_nodal_connec)
347     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
348       {
349         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
350         return false;
351       }
352   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
353     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
354       {
355         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
356         return false;
357       }
358   if(_nodal_connec_index!=otherC->_nodal_connec_index)
359     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
360       {
361         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
362         return false;
363       }
364   return true;
365 }
366
367 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
368 {
369   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
370   if(!otherC)
371     return false;
372   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
373     return false;
374   if(_mesh_dim!=otherC->_mesh_dim)
375     return false;
376   if(_types!=otherC->_types)
377     return false;
378   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
379     if(_nodal_connec==0 || otherC->_nodal_connec==0)
380       return false;
381   if(_nodal_connec!=otherC->_nodal_connec)
382     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
383       return false;
384   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
385     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
386       return false;
387   if(_nodal_connec_index!=otherC->_nodal_connec_index)
388     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
389       return false;
390   return true;
391 }
392
393 /*!
394  * 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
395  * in 'this' is found regarding 'prec' parameter and 'cellCompPol' parameter.
396  * 
397  * In case of success cellCor and nodeCor are informed both. 
398  * @param cellCompPol values are described in MEDCouplingUMesh::zipConnectivityTraducer method.
399  * @param cellCor output array giving the correspondance of cells from 'other' to 'this'.
400  * @param nodeCor output array giving the correspondance of nodes from 'other' to 'this'.
401  */
402 void MEDCouplingUMesh::checkDeepEquivalWith(const MEDCouplingMesh *other, int cellCompPol, double prec,
403                                             DataArrayInt *&cellCor, DataArrayInt *&nodeCor) const throw(INTERP_KERNEL::Exception)
404 {
405   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
406   if(!otherC)
407     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Two meshes are not not unstructured !");
408   MEDCouplingMesh::checkFastEquivalWith(other,prec);
409   if(_types!=otherC->_types)
410     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Types are not equal !");
411   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MergeUMeshes(this,otherC);
412   bool areNodesMerged;
413   int newNbOfNodes;
414   int oldNbOfNodes=getNumberOfNodes();
415   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=m->buildPermArrayForMergeNode(prec,oldNbOfNodes,areNodesMerged,newNbOfNodes);
416   //mergeNodes
417   if(!areNodesMerged)
418     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : Nodes are incompatible ! ");
419   const int *pt=std::find_if(da->getConstPointer()+oldNbOfNodes,da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),oldNbOfNodes-1));
420   if(pt!=da->getConstPointer()+da->getNbOfElems())
421     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : some nodes in other are not in this !");
422   m->renumberNodes(da->getConstPointer(),newNbOfNodes);
423   //
424   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodeCor2=da->substr(oldNbOfNodes);
425   da=m->mergeNodes(prec,areNodesMerged,newNbOfNodes);
426   
427   //
428   da=m->zipConnectivityTraducer(cellCompPol);
429   int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+getNumberOfCells());
430   pt=std::find_if(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
431   if(pt!=da->getConstPointer()+da->getNbOfElems())
432     throw INTERP_KERNEL::Exception("checkDeepEquivalWith : some cells in other are not in this !");
433   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellCor2=DataArrayInt::New();
434   cellCor2->alloc(otherC->getNumberOfCells(),1);
435   std::copy(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),cellCor2->getPointer());
436   bool nident=nodeCor2->isIdentity();
437   bool cident=cellCor2->isIdentity();
438   if(!nident) { nodeCor=nodeCor2; nodeCor2->incrRef(); } else nodeCor=0;
439   if(!cident) { cellCor=cellCor2; cellCor2->incrRef(); } else cellCor=0;
440 }
441
442 /*!
443  * 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
444  * in 'this' is found regarding 'prec' parameter and 'cellCompPol' parameter. The difference with MEDCouplingUMesh::checkDeepEquivalWith method is that
445  * coordinates of 'this' and 'other' are expected to be the same. If not an exception will be thrown.
446  * This method is close to MEDCouplingUMesh::areCellsIncludedIn except that this method throws exception !
447  * 
448  * In case of success cellCor are informed both. 
449  * @param cellCompPol values are described in MEDCouplingUMesh::zipConnectivityTraducer method.
450  * @param cellCor output array giving the correspondance of cells from 'other' to 'this'.
451  */
452 void MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith(const MEDCouplingMesh *other, int cellCompPol, double prec,
453                                                        DataArrayInt *&cellCor) const throw(INTERP_KERNEL::Exception)
454 {
455   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
456   if(!otherC)
457     throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : Two meshes are not not unstructured !");
458   MEDCouplingMesh::checkFastEquivalWith(other,prec);
459   if(_types!=otherC->_types)
460     throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : Types are not equal !");
461   if(_coords!=otherC->_coords)
462     throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : meshes do not share the same coordinates ! Use tryToShareSameCoordinates or call checkDeepEquivalWith !");
463   std::vector<const MEDCouplingUMesh *> ms(2);
464   ms[0]=this;
465   ms[1]=otherC;
466   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=MergeUMeshesOnSameCoords(ms);
467   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=m->zipConnectivityTraducer(cellCompPol);
468   int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+getNumberOfCells());
469   const int *pt=std::find_if(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
470   if(pt!=da->getConstPointer()+da->getNbOfElems())
471     {
472       throw INTERP_KERNEL::Exception("checkDeepEquivalOnSameNodesWith : some cells in other are not in this !");
473     }
474   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellCor2=DataArrayInt::New();
475   cellCor2->alloc(otherC->getNumberOfCells(),1);
476   std::copy(da->getConstPointer()+getNumberOfCells(),da->getConstPointer()+da->getNbOfElems(),cellCor2->getPointer());
477   if(!cellCor2->isIdentity()) { cellCor=cellCor2; cellCor2->incrRef(); } else cellCor=0;
478 }
479
480 /*!
481  * This method checks fastly that 'this' and 'other' are equal. 
482  */
483 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const throw(INTERP_KERNEL::Exception)
484 {
485   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
486   if(!otherC)
487     throw INTERP_KERNEL::Exception("checkFastEquivalWith : Two meshes are not not unstructured !");
488   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
489   int nbOfCells=getNumberOfCells();
490   if(nbOfCells<1)
491     return ;
492   bool status=true;
493   status&=areCellsFrom2MeshEqual(otherC,0,prec);
494   status&=areCellsFrom2MeshEqual(otherC,nbOfCells/2,prec);
495   status&=areCellsFrom2MeshEqual(otherC,nbOfCells-1,prec);
496   if(!status)
497     throw INTERP_KERNEL::Exception("checkFastEquivalWith : Two meshes are not equal because on 3 test cells some difference have been detected !");
498 }
499
500 /*!
501  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
502  * For speed reasons no check of this will be done.
503  */
504 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const throw(INTERP_KERNEL::Exception)
505 {
506   checkFullyDefined();
507   int nbOfNodes=getNumberOfNodes();
508   int *revNodalIndxPtr=new int[nbOfNodes+1];
509   revNodalIndx->useArray(revNodalIndxPtr,true,CPP_DEALLOC,nbOfNodes+1,1);
510   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
511   const int *conn=_nodal_connec->getConstPointer();
512   const int *connIndex=_nodal_connec_index->getConstPointer();
513   int nbOfCells=getNumberOfCells();
514   int nbOfEltsInRevNodal=0;
515   for(int eltId=0;eltId<nbOfCells;eltId++)
516     {
517       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
518       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
519       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
520         if(*iter>=0)//for polyhedrons
521           {
522             nbOfEltsInRevNodal++;
523             revNodalIndxPtr[(*iter)+1]++;
524           }
525     }
526   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
527   int *revNodalPtr=new int[nbOfEltsInRevNodal];
528   revNodal->useArray(revNodalPtr,true,CPP_DEALLOC,nbOfEltsInRevNodal,1);
529   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
530   for(int eltId=0;eltId<nbOfCells;eltId++)
531     {
532       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
533       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
534       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
535         if(*iter>=0)//for polyhedrons
536           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
537     }
538 }
539
540 /// @cond INTERNAL
541
542 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
543 {
544   return id;
545 }
546
547 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
548 {
549   if(!compute)
550     return id+1;
551   else
552     {
553       if(cm.getOrientationStatus(nb,conn1,conn2))
554         return id+1;
555       else
556         return -(id+1);
557     }
558 }
559
560 /// @endcond
561
562 /*!
563  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
564  * For speed reasons no check of this will be done.
565  * Given 'this' with spacedim equal to s and meshdim equal to p, this method returns a new allocated mesh
566  * lying on the same coordinates than 'this' and having a meshdim equal to p-1.
567  * The algorithm to compute this p-1 mesh is the following :
568  * For each cell in 'this' it splits into p-1 elements.
569  *   If this p-1 element does not already exists it is appended to the returned mesh
570  *   If this p-1 element already exists, it is not appended.
571  * This method returns or 4 arrays plus the returned mesh.
572  * '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.
573  * For a cell with a cellid c in 'this' it is constituted of cells in [desc+descIndx[c],desc+descIndex[c+1])
574  *
575  * 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.
576  * 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])
577  *
578  * \warning This method returns a mesh whose geometric type order in are \b not sorted.
579  * In view of the MED file writing, a renumbering of cells in returned mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
580  */
581 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const throw(INTERP_KERNEL::Exception)
582 {
583   return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
584 }
585
586 /*!
587  * WARNING this method do the assumption that connectivity lies on the coordinates set.
588  * For speed reasons no check of this will be done.
589  * This method differs from MEDCouplingUMesh::buildDescendingConnectivity method in that 'desc' is in different format.
590  * 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,
591  * 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 
592  * an array in relative "FORTRAN" mode.
593  *
594  * \warning This method returns a mesh whose geometric type order in are \b not sorted.
595  * In view of the MED file writing, a renumbering of cells in returned mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
596  */
597 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const throw(INTERP_KERNEL::Exception)
598 {
599   return buildDescendingConnectivityGen(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
600 }
601
602 /*!
603  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
604  * For speed reasons no check of this will be done. This method calls MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
605  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities are considered.
606  * The a cell with id 'cellId' its neighbors are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
607  *
608  * \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
609  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
610  * \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.
611  */
612 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const throw(INTERP_KERNEL::Exception)
613 {
614   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
615   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
616   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
617   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
618   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
619   meshDM1=0;
620   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
621 }
622
623 /*!
624  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm of MEDCouplingUMesh::computeNeighborsOfCells.
625  * 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,
626  * excluding a set of meshdim-1 cells in input descending connectivity.
627  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx input params are the result of MEDCouplingUMesh::buildDescendingConnectivity.
628  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities are considered.
629  * The a cell with id 'cellId' its neighbors are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
630  *
631  * \param [in] desc descending connectivity array.
632  * \param [in] descIndx descending connectivity index array used to walk through \b desc.
633  * \param [in] revDesc reverse descending connectivity array.
634  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc.
635  * \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
636  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
637  * \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.
638  */
639 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
640                                                   DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) throw(INTERP_KERNEL::Exception)
641 {
642   if(!desc || !descIndx || !revDesc || !revDescIndx)
643     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
644   const int *descPtr=desc->getConstPointer();
645   const int *descIPtr=descIndx->getConstPointer();
646   const int *revDescPtr=revDesc->getConstPointer();
647   const int *revDescIPtr=revDescIndx->getConstPointer();
648   //
649   int nbCells=descIndx->getNumberOfTuples()-1;
650   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> out0=DataArrayInt::New();
651   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
652   int *out1Ptr=out1->getPointer();
653   *out1Ptr++=0;
654   std::vector<int> out0v;
655   out0v.reserve(desc->getNumberOfTuples());
656   for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
657     {
658       for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
659         {
660           std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
661           s.erase(i);
662           out0v.insert(out0v.end(),s.begin(),s.end());
663         }
664       *out1Ptr=out0v.size();
665     }
666   out0->alloc((int)out0v.size(),1);
667   std::copy(out0v.begin(),out0v.end(),out0->getPointer());
668   neighbors=out0; out0->incrRef();
669   neighborsIndx=out1; out1->incrRef();
670 }
671
672 /// @cond INTERNAL
673
674 /*!
675  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
676  * For speed reasons no check of this will be done.
677  */
678 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const throw(INTERP_KERNEL::Exception)
679 {
680   checkConnectivityFullyDefined();
681   int nbOfCells=getNumberOfCells();
682   int nbOfNodes=getNumberOfNodes();
683   const int *conn=_nodal_connec->getConstPointer();
684   const int *connIndex=_nodal_connec_index->getConstPointer();
685   std::vector< std::vector<int> > descMeshConnB(nbOfCells);
686   std::vector< std::vector<int> > revDescMeshConnB;
687   std::vector< std::vector<int> > revNodalB(nbOfNodes);
688   std::vector<int> meshDM1Conn;
689   std::vector<int> meshDM1ConnIndex(1); meshDM1ConnIndex[0]=0;
690   std::vector<int> meshDM1Type;
691   for(int eltId=0;eltId<nbOfCells;eltId++)
692     {
693       int pos=connIndex[eltId];
694       int posP1=connIndex[eltId+1];
695       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
696       unsigned nbOfSons=cm.getNumberOfSons2(conn+pos+1,posP1-pos-1);
697       int *tmp=new int[posP1-pos];
698       for(unsigned i=0;i<nbOfSons;i++)
699         {
700           INTERP_KERNEL::NormalizedCellType cmsId;
701           unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
702           const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel(cmsId);
703           std::set<int> shareableCells(revNodalB[tmp[0]].begin(),revNodalB[tmp[0]].end());
704           for(unsigned j=1;j<nbOfNodesSon && !shareableCells.empty();j++)
705             {
706               std::set<int> tmp2(revNodalB[tmp[j]].begin(),revNodalB[tmp[j]].end());
707               std::set<int> tmp3;
708               std::set_intersection(tmp2.begin(),tmp2.end(),shareableCells.begin(),shareableCells.end(),inserter(tmp3,tmp3.begin()));
709               shareableCells=tmp3;
710             }
711           std::list<int> shareableCellsL(shareableCells.begin(),shareableCells.end());
712           std::set<int> ref(tmp,tmp+nbOfNodesSon);
713           for(std::list<int>::iterator iter=shareableCellsL.begin();iter!=shareableCellsL.end();)
714             {
715               if(cms.isCompatibleWith((INTERP_KERNEL::NormalizedCellType)meshDM1Type[*iter]))
716                 {
717                   std::set<int> ref2(meshDM1Conn.begin()+meshDM1ConnIndex[*iter],meshDM1Conn.begin()+meshDM1ConnIndex[(*iter)+1]);
718                   if(ref==ref2)
719                     break;
720                   else
721                     iter=shareableCellsL.erase(iter);
722                 }
723               else
724                 iter=shareableCellsL.erase(iter);
725             }
726           if(shareableCellsL.empty())
727             {
728               meshDM1Conn.insert(meshDM1Conn.end(),tmp,tmp+nbOfNodesSon);
729               meshDM1ConnIndex.push_back(meshDM1ConnIndex.back()+nbOfNodesSon);
730               int cellDM1Id=(int)meshDM1Type.size();
731               meshDM1Type.push_back((int)cmsId);
732               for(unsigned k=0;k<nbOfNodesSon;k++)
733                 revNodalB[tmp[k]].push_back(cellDM1Id);
734               revDescMeshConnB.resize(cellDM1Id+1);
735               revDescMeshConnB.back().push_back(eltId);
736               descMeshConnB[eltId].push_back(nbrer(cellDM1Id,0,cms,false,0,0));
737             }
738           else
739             {
740               int DM1cellId=shareableCellsL.front();
741               revDescMeshConnB[DM1cellId].push_back(eltId);
742               descMeshConnB[eltId].push_back(nbrer(DM1cellId,nbOfNodesSon,cms,true,tmp,&meshDM1Conn[meshDM1ConnIndex[DM1cellId]]));
743             }
744         }
745       delete [] tmp;
746     }
747   revNodalB.clear();
748   //
749   std::string name="Mesh constituent of "; name+=getName();
750   MEDCouplingUMesh *ret=MEDCouplingUMesh::New(name.c_str(),getMeshDimension()-1);
751   ret->setCoords(getCoords());
752   int nbOfCellsInConstituent=(int)meshDM1Type.size();
753   ret->allocateCells(nbOfCellsInConstituent);
754   revDescIndx->alloc(nbOfCellsInConstituent+1,1);
755   int *tmp3=revDescIndx->getPointer(); tmp3[0]=0;
756   for(int ii=0;ii<nbOfCellsInConstituent;ii++)
757     {
758       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)meshDM1Type[ii],meshDM1ConnIndex[ii+1]-meshDM1ConnIndex[ii],&meshDM1Conn[meshDM1ConnIndex[ii]]);
759       tmp3[ii+1]=tmp3[ii]+((int)revDescMeshConnB[ii].size());
760     }
761   ret->finishInsertingCells();
762   revDesc->alloc(tmp3[nbOfCellsInConstituent],1);
763   tmp3=revDesc->getPointer();
764   for(std::vector< std::vector<int> >::const_iterator iter2=revDescMeshConnB.begin();iter2!=revDescMeshConnB.end();iter2++)
765     tmp3=std::copy((*iter2).begin(),(*iter2).end(),tmp3);
766   meshDM1Type.clear(); meshDM1ConnIndex.clear(); meshDM1Conn.clear();
767   descIndx->alloc(nbOfCells+1,1);
768   tmp3=descIndx->getPointer(); tmp3[0]=0;
769   for(int jj=0;jj<nbOfCells;jj++)
770     tmp3[jj+1]=tmp3[jj]+((int)descMeshConnB[jj].size());
771   desc->alloc(tmp3[nbOfCells],1);
772   tmp3=desc->getPointer();
773   for(std::vector< std::vector<int> >::const_iterator iter3=descMeshConnB.begin();iter3!=descMeshConnB.end();iter3++)
774     tmp3=std::copy((*iter3).begin(),(*iter3).end(),tmp3);
775   //
776   return ret;
777 }
778
779 struct MEDCouplingAccVisit
780 {
781   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
782   int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
783   int _new_nb_of_nodes;
784 };
785
786 /// @endcond
787
788
789 /*!
790  * This method convert cell with ids in ['cellIdsToConvertBg','cellIdsToConvertEnd') into 'this' into dynamic types without changing geometry.
791  * That is to say if 'this' is a 2D, mesh after the invocation of this method it will contain only polygons.
792  * If 'this' is a 3D mesh after the invocation of this method it will contain only polyhedra.
793  * If mesh dimension is not in [2,3] an exception is thrown.
794  * Of course pay attention that the resulting mesh is slower than previous one.
795  * If in ['cellIdsToConvertBg','cellIdsToConvertEnd') there is a cell id not in [0,'this->getNumberOfCells()') an exception will be thrown.
796  * In this case if meshDim==2 the mesh is still valid and only cells treated before throw will be converted into polygon.
797  * If mesh==3, after throw the mesh is \b unconsistent !
798  * This method is above all designed to test more extensively algorithms able to deal with polygons/polyhedra.
799  * 
800  * \warning This method modifies can modify significantly the geometric type order in \a this.
801  * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
802  */
803 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
804 {
805   checkFullyDefined();
806   int dim=getMeshDimension();
807   if(dim<2 || dim>3)
808     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
809   int nbOfCells=getNumberOfCells();
810   if(dim==2)
811     {
812       const int *connIndex=_nodal_connec_index->getConstPointer();
813       int *conn=_nodal_connec->getPointer();
814       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
815         {
816           if(*iter>=0 && *iter<nbOfCells)
817             {
818               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
819               if(!cm.isDynamic())
820                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
821               else
822                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
823             }
824           else
825             {
826               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
827               oss << " in range [0," << nbOfCells << ") !";
828               throw INTERP_KERNEL::Exception(oss.str().c_str());
829             }
830         }
831     }
832   else
833     {
834       int *connIndex=_nodal_connec_index->getPointer();
835       int connIndexLgth=_nodal_connec_index->getNbOfElems();
836       const int *connOld=_nodal_connec->getConstPointer();
837       int connOldLgth=_nodal_connec->getNbOfElems();
838       std::vector<int> connNew(connOld,connOld+connOldLgth);
839       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
840         {
841           if(*iter>=0 && *iter<nbOfCells)
842             {
843               int pos=connIndex[*iter];
844               int posP1=connIndex[(*iter)+1];
845               int lgthOld=posP1-pos-1;
846               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connNew[pos]);
847               connNew[pos]=INTERP_KERNEL::NORM_POLYHED;
848               unsigned nbOfFaces=cm.getNumberOfSons2(&connNew[pos+1],lgthOld);
849               int *tmp=new int[nbOfFaces*lgthOld];
850               int *work=tmp;
851               for(int j=0;j<(int)nbOfFaces;j++)
852                 {
853                   INTERP_KERNEL::NormalizedCellType type;
854                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,&connNew[pos+1],lgthOld,work,type);
855                   work+=offset;
856                   *work++=-1;
857                 }
858               std::size_t newLgth=std::distance(tmp,work)-1;
859               std::size_t delta=newLgth-lgthOld;
860               std::transform(connIndex+(*iter)+1,connIndex+connIndexLgth,connIndex+(*iter)+1,std::bind2nd(std::plus<int>(),delta));
861               connNew.insert(connNew.begin()+posP1,tmp+lgthOld,tmp+newLgth);
862               std::copy(tmp,tmp+lgthOld,connNew.begin()+pos+1);
863               delete [] tmp;
864             }
865           else
866             {
867               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
868               oss << " in range [0," << nbOfCells << ") !";
869               throw INTERP_KERNEL::Exception(oss.str().c_str());
870             }
871         }
872       _nodal_connec->alloc((int)connNew.size(),1);
873       int *newConnPtr=_nodal_connec->getPointer();
874       std::copy(connNew.begin(),connNew.end(),newConnPtr);
875     }
876   computeTypes();
877 }
878
879 /*!
880  * This method converts all cells into poly type if possible.
881  * This method is purely for userfriendliness.
882  * As this method can be costly in Memory, no optimization is done to avoid construction of useless vector.
883  */
884 void MEDCouplingUMesh::convertAllToPoly()
885 {
886   int nbOfCells=getNumberOfCells();
887   std::vector<int> cellIds(nbOfCells);
888   for(int i=0;i<nbOfCells;i++)
889     cellIds[i]=i;
890   convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
891 }
892
893 /*!
894  * 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.
895  * This method work only on cells with type NORM_POLYHED, all other cells with different type, are remains unchanged.
896  * 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
897  * each 2 faces hidden in the single face of polyhedron).
898  * The first face is expected to be right oriented because all faces of this polyhedron will be deduced.
899  * When called 'this' is an invalid mesh on MED sense. This method will correct that for polyhedra.
900  * 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'
901  * remains unchanged.
902  * This method is usefull only for users that wants to build extruded unstructured mesh.
903  * This method is a convenient one that avoids boring polyhedra setting during insertNextCell process.
904  * In case of success, 'this' has be corrected contains the same number of cells and is valid in MED sense.
905  */
906 void MEDCouplingUMesh::convertExtrudedPolyhedra() throw(INTERP_KERNEL::Exception)
907 {
908   checkFullyDefined();
909   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
910     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
911   int nbOfCells=getNumberOfCells();
912   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newCi=DataArrayInt::New();
913   newCi->alloc(nbOfCells+1,1);
914   int *newci=newCi->getPointer();
915   const int *ci=_nodal_connec_index->getConstPointer();
916   const int *c=_nodal_connec->getConstPointer();
917   newci[0]=0;
918   for(int i=0;i<nbOfCells;i++)
919     {
920       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
921       if(type==INTERP_KERNEL::NORM_POLYHED)
922         {
923           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
924             {
925               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
926               throw INTERP_KERNEL::Exception(oss.str().c_str());
927             }
928           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
929           if(n2%2!=0)
930             {
931               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 !";
932               throw INTERP_KERNEL::Exception(oss.str().c_str());
933             }
934           int n1=(int)(n2/2);
935           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)
936         }
937       else
938         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
939     }
940   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newC=DataArrayInt::New();
941   newC->alloc(newci[nbOfCells],1);
942   int *newc=newC->getPointer();
943   for(int i=0;i<nbOfCells;i++)
944     {
945       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
946       if(type==INTERP_KERNEL::NORM_POLYHED)
947         {
948           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
949           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
950           *newc++=-1;
951           for(std::size_t j=0;j<n1;j++)
952             {
953               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
954               newc[n1+5*j]=-1;
955               newc[n1+5*j+1]=c[ci[i]+1+j];
956               newc[n1+5*j+2]=c[ci[i]+1+(j+1)%n1];
957               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
958               newc[n1+5*j+4]=c[ci[i]+1+j+n1];
959             }
960           newc+=n1*6;
961         }
962       else
963         newc=std::copy(c+ci[i],c+ci[i+1],newc);
964     }
965   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi;
966   _nodal_connec->decrRef(); _nodal_connec=newC;
967   newC->incrRef(); newCi->incrRef();
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   const double *coordsPtr=coords->getConstPointer();
1066   //
1067   int nbOfCells=getNumberOfCells();
1068   const int *conn=_nodal_connec->getConstPointer();
1069   const int *index=_nodal_connec_index->getConstPointer();
1070   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connINew=DataArrayInt::New();
1071   connINew->alloc(nbOfCells+1,1);
1072   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1073   std::vector<int> connNew;
1074   bool changed=false;
1075   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1076     {
1077       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1078         {
1079           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1080           changed=true;
1081         }
1082       else
1083         connNew.insert(connNew.end(),conn+index[i],conn+index[i+1]);
1084       *connINewPtr=(int)connNew.size();
1085     }
1086   if(changed)
1087     {
1088       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connNew2=DataArrayInt::New();
1089       connNew2->alloc((int)connNew.size(),1);
1090       std::copy(connNew.begin(),connNew.end(),connNew2->getPointer());
1091       setConnectivity(connNew2,connINew,false);
1092     }
1093 }
1094
1095 /*!
1096  * This method returns all node ids used in \b this. The data array returned has to be dealt by the caller.
1097  * The returned node ids are sortes ascendingly. This method is closed to MEDCouplingUMesh::getNodeIdsInUse except
1098  * the format of returned DataArrayInt instance.
1099  * 
1100  * @return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1101  * \sa MEDCouplingUMesh::getNodeIdsInUse
1102  */
1103 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const throw(INTERP_KERNEL::Exception)
1104 {
1105   checkConnectivityFullyDefined();
1106   std::set<int> retS;
1107   int nbOfCells=getNumberOfCells();
1108   const int *connIndex=_nodal_connec_index->getConstPointer();
1109   const int *conn=_nodal_connec->getConstPointer();
1110   for(int i=0;i<nbOfCells;i++)
1111     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1112       if(conn[j]>=0)
1113         retS.insert(conn[j]);
1114   DataArrayInt *ret=DataArrayInt::New();
1115   ret->alloc((int)retS.size(),1);
1116   std::copy(retS.begin(),retS.end(),ret->getPointer());
1117   return ret;
1118 }
1119
1120 /*!
1121  * Array returned is the correspondance in \b old \b to \b new format (that's why 'nbrOfNodesInUse' is returned too).
1122  * The returned array is newly created and should be dealt by the caller.
1123  * To retrieve the new to old format the user can use DataArrayInt::invertArrayO2N2N2O method.
1124  * The size of returned array is the number of nodes of 'this'.
1125  * -1 values in returned array means that the corresponding node never appear in any nodal connectivity of cells constituting 'this'.
1126  * @param [out] nbrOfNodesInUse out parameter that specifies how many of nodes in 'this' is really used in nodal connectivity.
1127  * @return a newly allocated DataArrayInt that tells for each nodeid in \b this if it is unused (-1) or used (the corresponding new id)
1128  */
1129 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const throw(INTERP_KERNEL::Exception)
1130 {
1131   nbrOfNodesInUse=-1;
1132   int nbOfNodes=getNumberOfNodes();
1133   DataArrayInt *ret=DataArrayInt::New();
1134   ret->alloc(nbOfNodes,1);
1135   int *traducer=ret->getPointer();
1136   std::fill(traducer,traducer+nbOfNodes,-1);
1137   int nbOfCells=getNumberOfCells();
1138   const int *connIndex=_nodal_connec_index->getConstPointer();
1139   const int *conn=_nodal_connec->getConstPointer();
1140   for(int i=0;i<nbOfCells;i++)
1141     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1142       if(conn[j]>=0)
1143         traducer[conn[j]]=1;
1144   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1145   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1146   return ret;
1147 }
1148
1149 /*!
1150  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1151  * For each cell in \b this the number of nodes constituting cell is computed.
1152  * Excepted for poyhedrons, the result can be deduced by performing a deltaShiftIndex on the nodal connectivity index in \b this minus 1.
1153  * For polyhedrons, the face separation (-1) are excluded from the couting.
1154  * 
1155  * \return a newly allocated array
1156  */
1157 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const throw(INTERP_KERNEL::Exception)
1158 {
1159   checkConnectivityFullyDefined();
1160   int nbOfCells=getNumberOfCells();
1161   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
1162   ret->alloc(nbOfCells,1);
1163   int *retPtr=ret->getPointer();
1164   const int *conn=getNodalConnectivity()->getConstPointer();
1165   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1166   for(int i=0;i<nbOfCells;i++,retPtr++)
1167     {
1168       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1169         *retPtr=connI[i+1]-connI[i]-1;
1170       else
1171         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1172     }
1173   ret->incrRef(); return ret;
1174 }
1175
1176 /*!
1177  * 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.
1178  * The maximum value stored in returned array is the number of nodes of 'this' minus 1 after call of this method.
1179  * The size of returned array is the number of nodes of the old (previous to the call of this method) number of nodes.
1180  * -1 values in returned array means that the corresponding old node is no more used.
1181  */
1182 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer() throw(INTERP_KERNEL::Exception)
1183 {
1184   int newNbOfNodes=-1;
1185   DataArrayInt *traducer=getNodeIdsInUse(newNbOfNodes);
1186   renumberNodes(traducer->getConstPointer(),newNbOfNodes);
1187   return traducer;
1188 }
1189
1190 /*!
1191  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1192  * The semantic of 'compType' is specified in MEDCouplingUMesh::zipConnectivityTraducer method.
1193  */
1194 int MEDCouplingUMesh::areCellsEqual(int cell1, int cell2, int compType) const
1195 {
1196   switch(compType)
1197     {
1198     case 0:
1199       return areCellsEqual0(cell1,cell2);
1200     case 1:
1201       return areCellsEqual1(cell1,cell2);
1202     case 2:
1203       return areCellsEqual2(cell1,cell2);
1204     case 7:
1205       return areCellsEqual7(cell1,cell2);
1206     }
1207   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1 or 2.");
1208 }
1209
1210 /*!
1211  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 0.
1212  */
1213 int MEDCouplingUMesh::areCellsEqual0(int cell1, int cell2) const
1214 {
1215   const int *conn=getNodalConnectivity()->getConstPointer();
1216   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1217   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1218     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1219   return 0;
1220 }
1221
1222 /*!
1223  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 1.
1224  */
1225 int MEDCouplingUMesh::areCellsEqual1(int cell1, int cell2) const
1226 {
1227   const int *conn=getNodalConnectivity()->getConstPointer();
1228   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1229   int sz=connI[cell1+1]-connI[cell1];
1230   if(sz==connI[cell2+1]-connI[cell2])
1231     {
1232       if(conn[connI[cell1]]==conn[connI[cell2]])
1233         {
1234           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1235           unsigned dim=cm.getDimension();
1236           if(dim!=3)
1237             {
1238               if(dim!=1)
1239                 {
1240                   int sz1=2*(sz-1);
1241                   int *tmp=new int[sz1];
1242                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],tmp);
1243                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1244                   work=std::search(tmp,tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1245                   delete [] tmp;
1246                   return work!=tmp+sz1?1:0;
1247                 }
1248               else
1249                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1250             }
1251           else
1252             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areCellsEqual1 : not implemented yet for meshdim == 3 !");
1253         }
1254     }
1255   return 0;
1256 }
1257
1258 /*!
1259  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 2.
1260  */
1261 int MEDCouplingUMesh::areCellsEqual2(int cell1, int cell2) const
1262 {
1263   const int *conn=getNodalConnectivity()->getConstPointer();
1264   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1265   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1266     {
1267       if(conn[connI[cell1]]==conn[connI[cell2]])
1268         {
1269           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1270           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1271           return s1==s2?1:0;
1272         }
1273     }
1274   return 0;
1275 }
1276
1277 /*!
1278  * This method is the last step of the MEDCouplingUMesh::zipConnectivityTraducer with policy 7.
1279  */
1280 int MEDCouplingUMesh::areCellsEqual7(int cell1, int cell2) const
1281 {
1282   const int *conn=getNodalConnectivity()->getConstPointer();
1283   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1284   int sz=connI[cell1+1]-connI[cell1];
1285   if(sz==connI[cell2+1]-connI[cell2])
1286     {
1287       if(conn[connI[cell1]]==conn[connI[cell2]])
1288         {
1289           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1290           unsigned dim=cm.getDimension();
1291           if(dim!=3)
1292             {
1293               if(dim!=1)
1294                 {
1295                   int sz1=2*(sz-1);
1296                   int *tmp=new int[sz1];
1297                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],tmp);
1298                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1299                   work=std::search(tmp,tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1300                   if(work!=tmp+sz1)
1301                     {
1302                       delete [] tmp;
1303                       return 1;
1304                     }
1305                   else
1306                     {
1307                       std::reverse_iterator<int *> it1(tmp+sz1);
1308                       std::reverse_iterator<int *> it2(tmp);
1309                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1310                         {
1311                           delete [] tmp;
1312                           return 2;
1313                         }
1314                       else
1315                         {
1316                           delete [] tmp;
1317                           return 0;
1318                         }
1319                     }
1320                   
1321                   return work!=tmp+sz1?1:0;
1322                 }
1323               else
1324                 {//case of SEG2 and SEG3
1325                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1326                     return 1;
1327                   if(!cm.isQuadratic())
1328                     {
1329                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1330                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1331                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1332                         return 2;
1333                       return 0;
1334                     }
1335                   else
1336                     {
1337                       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])
1338                         return 2;
1339                       return 0;
1340                     }
1341                 }
1342             }
1343           else
1344             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areCellsEqual7 : not implemented yet for meshdim == 3 !");
1345         }
1346     }
1347   return 0;
1348 }
1349
1350
1351 /*!
1352  * This method compares 2 cells coming from two unstructured meshes : 'this' and 'other'.
1353  * This method compares 2 cells having the same id 'cellId' in 'this' and 'other'.
1354  */
1355 bool MEDCouplingUMesh::areCellsFrom2MeshEqual(const MEDCouplingUMesh *other, int cellId, double prec) const
1356 {
1357   if(getTypeOfCell(cellId)!=other->getTypeOfCell(cellId))
1358     return false;
1359   std::vector<int> c1,c2;
1360   getNodeIdsOfCell(cellId,c1);
1361   other->getNodeIdsOfCell(cellId,c2);
1362   std::size_t sz=c1.size();
1363   if(sz!=c2.size())
1364     return false;
1365   for(std::size_t i=0;i<sz;i++)
1366     {
1367       std::vector<double> n1,n2;
1368       getCoordinatesOfNode(c1[0],n1);
1369       other->getCoordinatesOfNode(c2[0],n2);
1370       std::transform(n1.begin(),n1.end(),n2.begin(),n1.begin(),std::minus<double>());
1371       std::transform(n1.begin(),n1.end(),n1.begin(),std::ptr_fun<double,double>(fabs));
1372       if(*std::max_element(n1.begin(),n1.end())>prec)
1373         return false;
1374     }
1375   return true;
1376 }
1377
1378 /*!
1379  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1380  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1381  * and result remains unchanged.
1382  * The semantic of 'compType' is specified in MEDCouplingUMesh::zipConnectivityTraducer method.
1383  * If in 'candidates' pool -1 value is considered as an empty value.
1384  * WARNING this method returns only ONE set of result !
1385  */
1386 bool MEDCouplingUMesh::areCellsEqualInPool(const std::vector<int>& candidates, int compType, std::vector<int>& result) const
1387 {
1388   std::set<int> cand(candidates.begin(),candidates.end());
1389   cand.erase(-1);
1390   if(cand.size()<=1)
1391     return false;
1392   bool ret=false;
1393   std::set<int>::const_iterator iter=cand.begin();
1394   int start=(*iter++);
1395   for(;iter!=cand.end();iter++)
1396     {
1397       int status=areCellsEqual(start,*iter,compType);
1398       if(status!=0)
1399         {
1400           if(!ret)
1401             {
1402               result.push_back(start);
1403               ret=true;
1404             }
1405           if(status==1)
1406             result.push_back(*iter);
1407           else
1408             result.push_back(status==2?(*iter+1):-(*iter+1));
1409         }
1410     }
1411   return ret;
1412 }
1413
1414 /*!
1415  * This method common cells base regarding 'compType' comparison policy described in ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer for details.
1416  * This method returns 2 values 'res' and 'resI'.
1417  * If 'res' and 'resI' are not empty before calling this method they will be cleared before set.
1418  * The format of 'res' and 'resI' is as explained here.
1419  * resI.size()-1 is the number of set of cells equal.
1420  * The nth set is [res.begin()+resI[n];res.begin()+resI[n+1]) with 0<=n<resI.size()-1 
1421  */
1422 template<int SPACEDIM>
1423 void MEDCouplingUMesh::findCommonCellsBase(int compType, std::vector<int>& res, std::vector<int>& resI) const
1424 {
1425   res.clear(); resI.clear();
1426   resI.push_back(0);
1427   std::vector<double> bbox;
1428   int nbOfCells=getNumberOfCells();
1429   getBoundingBoxForBBTree(bbox);
1430   double bb[2*SPACEDIM];
1431   double eps=getCaracteristicDimension();
1432   eps*=1.e-12;
1433   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
1434   const int *conn=getNodalConnectivity()->getConstPointer();
1435   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1436   const double *coords=getCoords()->getConstPointer();
1437   std::vector<bool> isFetched(nbOfCells);
1438   for(int k=0;k<nbOfCells;k++)
1439     {
1440       if(!isFetched[k])
1441         {
1442           for(int j=0;j<SPACEDIM;j++)
1443             { bb[2*j]=std::numeric_limits<double>::max(); bb[2*j+1]=-std::numeric_limits<double>::max(); }
1444           for(const int *pt=conn+connI[k]+1;pt!=conn+connI[k+1];pt++)
1445             if(*pt>-1)
1446               {
1447                 for(int j=0;j<SPACEDIM;j++)
1448                   {
1449                     bb[2*j]=std::min(bb[2*j],coords[SPACEDIM*(*pt)+j]);
1450                     bb[2*j+1]=std::max(bb[2*j+1],coords[SPACEDIM*(*pt)+j]);
1451                   }
1452               }
1453           std::vector<int> candidates1;
1454           myTree.getIntersectingElems(bb,candidates1);
1455           std::vector<int> candidates;
1456           for(std::vector<int>::const_iterator iter=candidates1.begin();iter!=candidates1.end();iter++)
1457             if(!isFetched[*iter])
1458               candidates.push_back(*iter);
1459           if(areCellsEqualInPool(candidates,compType,res))
1460             {
1461               int pos=resI.back();
1462               resI.push_back((int)res.size());
1463               for(std::vector<int>::const_iterator it=res.begin()+pos;it!=res.end();it++)
1464                 isFetched[*it]=true;
1465             }
1466           isFetched[k]=true;
1467         }
1468     }
1469 }
1470
1471 /*!
1472  * This method could potentially modify 'this'. This method merges cells if there are cells equal in 'this'. The comparison is specified by 'compType'.
1473  * This method keeps the coordiantes of 'this'.
1474  *
1475  * @param compType input specifying the technique used to compare cells each other.
1476  *   - 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.
1477  *   - 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)
1478  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1479  *   - 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
1480  * can be used for users not sensitive to orientation of cell
1481  * @return the correspondance array old to new.
1482  * 
1483  * \warning This method modifies can modify significantly the geometric type order in \a this.
1484  * In view of the MED file writing, a renumbering of cells in \a this (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1485  */
1486 DataArrayInt *MEDCouplingUMesh::zipConnectivityTraducer(int compType) throw(INTERP_KERNEL::Exception)
1487 {
1488   int spaceDim=getSpaceDimension();
1489   int nbOfCells=getNumberOfCells();
1490   std::vector<int> commonCells;
1491   std::vector<int> commonCellsI;
1492   switch(spaceDim)
1493     {
1494     case 3:
1495       {
1496         findCommonCellsBase<3>(compType,commonCells,commonCellsI);
1497         break;
1498       }
1499     case 2:
1500       {
1501         findCommonCellsBase<2>(compType,commonCells,commonCellsI);
1502         break;
1503       }
1504     case 1:
1505       {
1506         findCommonCellsBase<1>(compType,commonCells,commonCellsI);
1507         break;
1508       }
1509     default:
1510       throw INTERP_KERNEL::Exception("Invalid spaceDimension : must be 1, 2 or 3.");
1511     }
1512   DataArrayInt *ret=DataArrayInt::New();
1513   ret->alloc(nbOfCells,1);
1514   int *retPtr=ret->getPointer();
1515   std::fill(retPtr,retPtr+nbOfCells,0);
1516   const std::size_t nbOfTupleSmCells=commonCellsI.size()-1;
1517   int id=-1;
1518   std::vector<int> cellsToKeep;
1519   for(std::size_t i=0;i<nbOfTupleSmCells;i++)
1520     {
1521       for(std::vector<int>::const_iterator it=commonCells.begin()+commonCellsI[i];it!=commonCells.begin()+commonCellsI[i+1];it++)
1522         retPtr[*it]=id;
1523       id--;
1524     }
1525   id=0;
1526   std::map<int,int> m;
1527   for(int i=0;i<nbOfCells;i++)
1528     {
1529       int val=retPtr[i];
1530       if(val==0)
1531         {
1532           retPtr[i]=id++;
1533           cellsToKeep.push_back(i);
1534         }
1535       else
1536         {
1537           std::map<int,int>::const_iterator iter=m.find(val);
1538           if(iter==m.end())
1539             {
1540               m[val]=id;
1541               retPtr[i]=id++;
1542               cellsToKeep.push_back(i);
1543             }
1544           else
1545             retPtr[i]=(*iter).second;
1546         }
1547     }
1548   MEDCouplingUMesh *self=(MEDCouplingUMesh *)buildPartOfMySelf(&cellsToKeep[0],&cellsToKeep[0]+cellsToKeep.size(),true);
1549   setConnectivity(self->getNodalConnectivity(),self->getNodalConnectivityIndex(),true);
1550   self->decrRef();
1551   return ret;
1552 }
1553
1554 /*!
1555  * This method makes the assumption that 'this' and 'other' share the same coords. If not an exception will be thrown !
1556  * 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. 
1557  * This method is close to MEDCouplingUMesh::checkDeepEquivalOnSameNodesWith or MEDCouplingMesh::checkGeoEquivalWith with policy 20,21,or 22.
1558  * The main difference is that this method is not expected to throw exception.
1559  * This method has two outputs :
1560  *
1561  * @param compType is the comparison type. The possible values of this parameter are described in ParaMEDMEM::MEDCouplingUMesh::zipConnectivityTraducer method
1562  * @param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1563  * @return If 'other' is fully included in 'this 'true is returned. If not false is returned.
1564  */
1565 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const throw(INTERP_KERNEL::Exception)
1566 {
1567   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1568   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType);
1569   int nbOfCells=getNumberOfCells();
1570   arr=o2n->substr(nbOfCells);
1571   arr->setName(other->getName());
1572   int tmp;
1573   if(other->getNumberOfCells()==0)
1574     return true;
1575   return arr->getMaxValue(tmp)<nbOfCells;
1576 }
1577
1578 /*!
1579  * This method makes the assumption that 'this' and 'other' share the same coords. If not an exception will be thrown !
1580  * This method tries to determine if \b other is fully included in \b this.
1581  * The main difference is that this method is not expected to throw exception.
1582  * This method has two outputs :
1583  *
1584  * @param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1585  * @return If 'other' is fully included in 'this 'true is returned. If not false is returned.
1586  */
1587 bool MEDCouplingUMesh::areCellsIncludedIn2(const MEDCouplingUMesh *other, DataArrayInt *& arr) const throw(INTERP_KERNEL::Exception)
1588 {
1589   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1590   int spaceDim=mesh->getSpaceDimension();
1591   std::vector<int> commonCells;
1592   std::vector<int> commonCellsI;
1593   switch(spaceDim)
1594     {
1595     case 3:
1596       {
1597         findCommonCellsBase<3>(7,commonCells,commonCellsI);
1598         break;
1599       }
1600     case 2:
1601       {
1602         findCommonCellsBase<2>(7,commonCells,commonCellsI);
1603         break;
1604       }
1605     case 1:
1606       {
1607         findCommonCellsBase<1>(7,commonCells,commonCellsI);
1608         break;
1609       }
1610     default:
1611       throw INTERP_KERNEL::Exception("Invalid spaceDimension : must be 1, 2 or 3.");
1612     }
1613   int thisNbCells=getNumberOfCells();
1614   int otherNbCells=other->getNumberOfCells();
1615   int nbOfCells=mesh->getNumberOfCells();
1616   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arr2=DataArrayInt::New();
1617   arr2->alloc(otherNbCells,1);
1618   arr2->fillWithZero();
1619   int *arr2Ptr=arr2->getPointer();
1620   int nbOfCommon=(int)commonCellsI.size()-1;
1621   for(int i=0;i<nbOfCommon;i++)
1622     {
1623       int start=commonCells[commonCellsI[i]];
1624       if(start<thisNbCells)
1625         {
1626           for(int j=commonCellsI[i]+1;j!=commonCellsI[i+1];j++)
1627             {
1628               int sig=commonCells[j]>0?1:-1;
1629               int val=std::abs(commonCells[j])-1;
1630               if(val>=thisNbCells)
1631                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1632             }
1633         }
1634     }
1635   arr2->setName(other->getName());
1636   if(arr2->presenceOfValue(0))
1637     return false;
1638   arr=arr2;
1639   arr2->incrRef();
1640   return true;
1641 }
1642
1643 /*!
1644  * @param areNodesMerged if at least two nodes have been merged.
1645  * @return old to new node correspondance.
1646  */
1647 DataArrayInt *MEDCouplingUMesh::mergeNodes(double precision, bool& areNodesMerged, int& newNbOfNodes)
1648 {
1649   DataArrayInt *ret=buildPermArrayForMergeNode(precision,-1,areNodesMerged,newNbOfNodes);
1650   if(areNodesMerged)
1651     renumberNodes(ret->getConstPointer(),newNbOfNodes);
1652   return ret;
1653 }
1654
1655 /*!
1656  * Idem ParaMEDMEM::MEDCouplingUMesh::mergeNodes method except that the merged nodes are meld into the barycenter of them.
1657  */
1658 DataArrayInt *MEDCouplingUMesh::mergeNodes2(double precision, bool& areNodesMerged, int& newNbOfNodes)
1659 {
1660   DataArrayInt *ret=buildPermArrayForMergeNode(precision,-1,areNodesMerged,newNbOfNodes);
1661   if(areNodesMerged)
1662     renumberNodes2(ret->getConstPointer(),newNbOfNodes);
1663   return ret;
1664 }
1665
1666 /*!
1667  * This method tries to use 'other' coords and use it for 'this'. If no exception was thrown after the call of this method :
1668  * this->_coords==other->_coords. If an exception is thrown 'this' remains unchanged.
1669  * Contrary to MEDCouplingUMesh::tryToShareSameCoords method this method makes a deeper analyze of coordinates (and so more expensive) than simple equality.
1670  * Two nodes one in 'this' and other in 'other' are considered equal if the distance between the two is lower than epsilon.
1671  */
1672 void MEDCouplingUMesh::tryToShareSameCoordsPermute(const MEDCouplingPointSet& other, double epsilon) throw(INTERP_KERNEL::Exception)
1673 {
1674   const DataArrayDouble *coords=other.getCoords();
1675   if(!coords)
1676     throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute : No coords specified in other !");
1677   if(!_coords)
1678     throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute : No coords specified in this whereas there is any in other !");
1679   int otherNbOfNodes=other.getNumberOfNodes();
1680   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=MergeNodesArray(&other,this);
1681   _coords->incrRef();
1682   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> oldCoords=_coords;
1683   setCoords(newCoords);
1684   bool areNodesMerged;
1685   int newNbOfNodes;
1686   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> da=buildPermArrayForMergeNode(epsilon,otherNbOfNodes,areNodesMerged,newNbOfNodes);
1687   if(!areNodesMerged)
1688     {
1689       setCoords(oldCoords);
1690       throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute fails : no nodes are mergeable with specified given epsilon !");
1691     }
1692   int maxId=*std::max_element(da->getConstPointer(),da->getConstPointer()+otherNbOfNodes);
1693   const int *pt=std::find_if(da->getConstPointer()+otherNbOfNodes,da->getConstPointer()+da->getNbOfElems(),std::bind2nd(std::greater<int>(),maxId));
1694   if(pt!=da->getConstPointer()+da->getNbOfElems())
1695     {
1696       setCoords(oldCoords);
1697       throw INTERP_KERNEL::Exception("tryToShareSameCoordsPermute fails : some nodes in this are not in other !");
1698     }
1699   setCoords(oldCoords);
1700   renumberNodesInConn(da->getConstPointer()+otherNbOfNodes);
1701   setCoords(coords);
1702 }
1703
1704 /*!
1705  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1706  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1707  * cellIds is not given explicitely but by a range python like.
1708  * 
1709  * \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.
1710  * \return a newly allocated
1711  * 
1712  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1713  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1714  */
1715 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf2(int start, int end, int step, bool keepCoords) const throw(INTERP_KERNEL::Exception)
1716 {
1717   if(getMeshDimension()!=-1)
1718     {
1719       MEDCouplingUMesh *ret=buildPartOfMySelfKeepCoords2(start,end,step);
1720       if(!keepCoords)
1721         ret->zipCoords();
1722       return ret;
1723     }
1724   else
1725     {
1726       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelf2 for -1 dimension mesh ");
1727       if(newNbOfCells!=1)
1728         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1729       if(start!=0)
1730         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1731       incrRef();
1732       return const_cast<MEDCouplingUMesh *>(this);
1733     }
1734 }
1735
1736 /*!
1737  * build a sub part of \b this. This sub part is defined by the cell ids contained in the array in [begin,end).
1738  * @param begin begin of array containing the cell ids to keep.
1739  * @param end end of array of cell ids to keep. \b WARNING end param is \b not included ! Idem STL standard definitions.
1740  * @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.
1741  * 
1742  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1743  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1744  */
1745 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
1746 {
1747   if(getMeshDimension()!=-1)
1748     {
1749       MEDCouplingUMesh *ret=buildPartOfMySelfKeepCoords(begin,end);
1750       if(!keepCoords)
1751         ret->zipCoords();
1752       return ret;
1753     }
1754   else
1755     {
1756       if(end-begin!=1)
1757         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1758       if(begin[0]!=0)
1759         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1760       incrRef();
1761       return const_cast<MEDCouplingUMesh *>(this);
1762     }
1763 }
1764
1765 /*!
1766  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1767  *
1768  * 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.
1769  * Size of [\b cellIdsBg, \b cellIdsEnd) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1770  * The number of cells of \b this will remain the same with this method.
1771  *
1772  * \param [in] begin begin of cell ids (included) of cells in this to assign
1773  * \param [in] end end of cell ids (excluded) of cells in this to assign
1774  * \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).
1775  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1776  */
1777 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis) throw(INTERP_KERNEL::Exception)
1778 {
1779   checkConnectivityFullyDefined();
1780   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1781   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1782     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1783   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1784     {
1785       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1786       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1787       throw INTERP_KERNEL::Exception(oss.str().c_str());
1788     }
1789   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
1790   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1791     {
1792       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1793       throw INTERP_KERNEL::Exception(oss.str().c_str());
1794     }
1795   int nbOfCells=getNumberOfCells();
1796   bool easyAssign=true;
1797   const int *conn=_nodal_connec->getConstPointer();
1798   const int *connI=_nodal_connec_index->getConstPointer();
1799   const int *connOther=otherOnSameCoordsThanThis._nodal_connec->getConstPointer();
1800   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1801   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
1802     {
1803       if(*it>=0 && *it<nbOfCells)
1804         {
1805           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
1806         }
1807       else
1808         {
1809           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
1810           throw INTERP_KERNEL::Exception(oss.str().c_str());
1811         }
1812     }
1813   if(easyAssign)
1814     {
1815       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1816       computeTypes();
1817     }
1818   else
1819     {
1820       DataArrayInt *arrOut=0,*arrIOut=0;
1821       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1822                                                arrOut,arrIOut);
1823       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1824       setConnectivity(arrOut,arrIOut,true);
1825     }
1826 }
1827
1828 void MEDCouplingUMesh::setPartOfMySelf2(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis) throw(INTERP_KERNEL::Exception)
1829 {
1830   checkConnectivityFullyDefined();
1831   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
1832   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
1833     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf2 : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
1834   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
1835     {
1836       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
1837       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
1838       throw INTERP_KERNEL::Exception(oss.str().c_str());
1839     }
1840   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelf2 : ");
1841   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
1842     {
1843       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
1844       throw INTERP_KERNEL::Exception(oss.str().c_str());
1845     }
1846   int nbOfCells=getNumberOfCells();
1847   bool easyAssign=true;
1848   const int *conn=_nodal_connec->getConstPointer();
1849   const int *connI=_nodal_connec_index->getConstPointer();
1850   const int *connOther=otherOnSameCoordsThanThis._nodal_connec->getConstPointer();
1851   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
1852   int it=start;
1853   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
1854     {
1855       if(it>=0 && it<nbOfCells)
1856         {
1857           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
1858         }
1859       else
1860         {
1861           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf2 : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
1862           throw INTERP_KERNEL::Exception(oss.str().c_str());
1863         }
1864     }
1865   if(easyAssign)
1866     {
1867       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
1868       computeTypes();
1869     }
1870   else
1871     {
1872       DataArrayInt *arrOut=0,*arrIOut=0;
1873       MEDCouplingUMesh::SetPartOfIndexedArrays2(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
1874                                                 arrOut,arrIOut);
1875       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
1876       setConnectivity(arrOut,arrIOut,true);
1877     }
1878 }                      
1879
1880 DataArrayInt *MEDCouplingUMesh::getCellIdsFullyIncludedInNodeIds(const int *partBg, const int *partEnd) const
1881 {
1882   std::vector<int> cellIdsKept;
1883   fillCellIdsToKeepFromNodeIds(partBg,partEnd,true,cellIdsKept);
1884   DataArrayInt *ret=DataArrayInt::New();
1885   ret->alloc((int)cellIdsKept.size(),1);
1886   std::copy(cellIdsKept.begin(),cellIdsKept.end(),ret->getPointer());
1887   return ret;
1888 }
1889
1890 /*!
1891  * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
1892  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
1893  * Parameter 'fullyIn' specifies if a cell that has part of its nodes in ids array is kept or not.
1894  * If 'fullyIn' is true only cells whose ids are \b fully contained in ['begin','end') tab will be kept.
1895  *
1896  * @param begin input start of array of node ids.
1897  * @param end input end of array of node ids.
1898  * @param fullyIn input that specifies if all node ids must be in ['begin','end') array to consider cell to be in.
1899  * @param cellIdsKept in/out array where all candidate cell ids are put at the end.
1900  */
1901 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, std::vector<int>& cellIdsKept) const
1902 {
1903   std::set<int> fastFinder(begin,end);
1904   int nbOfCells=getNumberOfCells();
1905   const int *conn=getNodalConnectivity()->getConstPointer();
1906   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
1907   for(int i=0;i<nbOfCells;i++)
1908     {
1909       std::set<int> connOfCell(conn+connIndex[i]+1,conn+connIndex[i+1]);
1910       connOfCell.erase(-1);//polyhedron separator
1911       int refLgth=(int)connOfCell.size();
1912       std::set<int> locMerge;
1913       std::insert_iterator< std::set<int> > it(locMerge,locMerge.begin());
1914       std::set_intersection(connOfCell.begin(),connOfCell.end(),fastFinder.begin(),fastFinder.end(),it);
1915       if(((int)locMerge.size()==refLgth && fullyIn) || (locMerge.size()!=0 && !fullyIn))
1916         cellIdsKept.push_back(i);
1917     }
1918 }
1919
1920 /*!
1921  * This method is very close too MEDCouplingUMesh::buildPartOfMySelfNode. The difference is that it returns directly ids.
1922  */
1923 DataArrayInt *MEDCouplingUMesh::getCellIdsLyingOnNodes(const int *begin, const int *end, bool fullyIn) const
1924 {
1925   std::vector<int> cellIdsKept;
1926   fillCellIdsToKeepFromNodeIds(begin,end,fullyIn,cellIdsKept);
1927   DataArrayInt *ret=DataArrayInt::New();
1928   ret->alloc((int)cellIdsKept.size(),1);
1929   std::copy(cellIdsKept.begin(),cellIdsKept.end(),ret->getPointer());
1930   ret->setName(getName());
1931   return ret;
1932 }
1933
1934 /*!
1935  * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
1936  * The return newly allocated mesh will share the same coordinates as 'this'.
1937  * Parameter 'fullyIn' specifies if a cell that has part of its nodes in ids array is kept or not.
1938  * If 'fullyIn' is true only cells whose ids are \b fully contained in ['begin','end') tab will be kept.
1939  */
1940 MEDCouplingPointSet *MEDCouplingUMesh::buildPartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
1941 {
1942   std::vector<int> cellIdsKept;
1943   fillCellIdsToKeepFromNodeIds(begin,end,fullyIn,cellIdsKept);
1944   return buildPartOfMySelf(&cellIdsKept[0],&cellIdsKept[0]+cellIdsKept.size(),true);
1945 }
1946
1947 /*!
1948  * Contrary to MEDCouplingUMesh::buildPartOfMySelfNode method this method builds a mesh with a meshDimension equal to
1949  * this->getMeshDimension()-1. The return newly allocated mesh will share the same coordinates as 'this'.
1950  * Parameter 'fullyIn' specifies if a face that has part of its nodes in ids array is kept or not.
1951  * If 'fullyIn' is true only faces whose ids are \b fully contained in ['begin','end') tab will be kept.
1952  */
1953 MEDCouplingPointSet *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
1954 {
1955   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
1956   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
1957   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1958   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
1959   return subMesh->buildPartOfMySelfNode(begin,end,fullyIn);
1960 }
1961
1962 /*!
1963  * This method returns a mesh with meshDim=this->getMeshDimension()-1.
1964  * This returned mesh contains cells that are linked with one and only one cell of this.
1965  * @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.
1966  * @return mesh with ref counter equal to 1.
1967  */
1968 MEDCouplingPointSet *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
1969 {
1970   DataArrayInt *desc=DataArrayInt::New();
1971   DataArrayInt *descIndx=DataArrayInt::New();
1972   DataArrayInt *revDesc=DataArrayInt::New();
1973   DataArrayInt *revDescIndx=DataArrayInt::New();
1974   //
1975   MEDCouplingUMesh *meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1976   revDesc->decrRef();
1977   desc->decrRef();
1978   descIndx->decrRef();
1979   int nbOfCells=meshDM1->getNumberOfCells();
1980   const int *revDescIndxC=revDescIndx->getConstPointer();
1981   std::vector<int> boundaryCells;
1982   for(int i=0;i<nbOfCells;i++)
1983     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
1984       boundaryCells.push_back(i);
1985   revDescIndx->decrRef();
1986   MEDCouplingPointSet *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
1987   meshDM1->decrRef();
1988   return ret;
1989 }
1990
1991 /*!
1992  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
1993  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
1994  * This method makes the assumption that 'this' is fully defined (coords,connectivity). If not an exception will be thrown. 
1995  */
1996 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const throw(INTERP_KERNEL::Exception)
1997 {
1998   checkFullyDefined();
1999   DataArrayInt *desc=DataArrayInt::New();
2000   DataArrayInt *descIndx=DataArrayInt::New();
2001   DataArrayInt *revDesc=DataArrayInt::New();
2002   DataArrayInt *revDescIndx=DataArrayInt::New();
2003   //
2004   MEDCouplingUMesh *meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2005   meshDM1->decrRef();
2006   desc->decrRef();
2007   descIndx->decrRef();
2008   //
2009   DataArrayInt *tmp=revDescIndx->deltaShiftIndex();
2010   DataArrayInt *faceIds=tmp->getIdsEqual(1);
2011   tmp->decrRef();
2012   int nbOfFaces=faceIds->getNumberOfTuples();
2013   const int *faces=faceIds->getConstPointer();
2014   std::set<int> ret;
2015   for(const int *w=faces;w!=faces+nbOfFaces;w++)
2016     ret.insert(revDesc->getIJ(revDescIndx->getIJ(*w,0),0));
2017   faceIds->decrRef();
2018   //
2019   revDescIndx->decrRef();
2020   revDesc->decrRef();
2021   //
2022   DataArrayInt *ret2=DataArrayInt::New();
2023   ret2->alloc((int)ret.size(),1);
2024   std::copy(ret.begin(),ret.end(),ret2->getPointer());
2025   ret2->setName("BoundaryCells");
2026   return ret2;
2027 }
2028
2029 /*!
2030  * This method find in \b this cells ids that lie on mesh \b otherDimM1OnSameCoords.
2031  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2032  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2033  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2034  *
2035  * s0 is the cells ids set in \b this lying on at least one node in fetched nodes in \b otherDimM1OnSameCoords.
2036  * This method method returns cells ids set s = s1 + s2 where :
2037  * 
2038  *  - s1 are cells ids in \b this whose dim-1 constituent equals a cell in \b otherDimM1OnSameCoords.
2039  *  - s2 are cells ids in \b s0 - \b s1 whose at least two neighbors are in s1.
2040  *
2041  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2042  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2043  *
2044  * \param [out] cellIdsRk0 a newly allocated array containing cells ids in \b this containg s0 in above algorithm.
2045  * \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
2046  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2047  */
2048 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const throw(INTERP_KERNEL::Exception)
2049 {
2050   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2051     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2052   checkConnectivityFullyDefined();
2053   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2054   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2055     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2056   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2057   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2058   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2059   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2060   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2061   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2062   DataArrayInt *idsOtherInConsti=0;
2063   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2064   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2065   if(!b)
2066     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2067   std::set<int> s1;
2068   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2069     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2070   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2071   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1Comparr_renum1=s1arr_renum1->buildComplement(s0arr->getNumberOfTuples());
2072   DataArrayInt *neighThisPart=0,*neighIThisPart=0;
2073   ComputeNeighborsOfCellsAdv(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart,neighThisPart,neighIThisPart);
2074   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighThisPartAuto(neighThisPart),neighIThisPartAuto(neighIThisPart);
2075   ExtractFromIndexedArrays(s1Comparr_renum1->begin(),s1Comparr_renum1->end(),neighThisPart,neighIThisPart,neighThisPart,neighIThisPart);// reuse of neighThisPart and neighIThisPart
2076   neighThisPartAuto=neighThisPart; neighIThisPartAuto=neighIThisPart;
2077   RemoveIdsFromIndexedArrays(s1Comparr_renum1->begin(),s1Comparr_renum1->end(),neighThisPart,neighIThisPart);
2078   neighThisPartAuto=0;
2079   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2_tmp=neighIThisPart->deltaShiftIndex();
2080   const int li[2]={0,1};
2081   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2_renum2=s2_tmp->getIdsNotEqualList(li,li+2);
2082   s2_renum2->transformWithIndArr(s1Comparr_renum1->begin(),s1Comparr_renum1->end());//s2_renum2==s2_renum1
2083   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s_renum1=DataArrayInt::Aggregate(s2_renum2,s1arr_renum1,0);
2084   s_renum1->sort();
2085   //
2086   s0arr->incrRef(); cellIdsRk0=s0arr;
2087   s_renum1->incrRef(); cellIdsRk1=s_renum1;
2088 }
2089
2090 /*!
2091  * 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
2092  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2093  * 
2094  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2095  */
2096 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const throw(INTERP_KERNEL::Exception)
2097 {
2098   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc=DataArrayInt::New();
2099   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx=DataArrayInt::New();
2100   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc=DataArrayInt::New();
2101   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx=DataArrayInt::New();
2102   //
2103   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2104   revDesc=0; desc=0; descIndx=0;
2105   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2106   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> part=revDescIndx2->getIdsEqual(1);
2107   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2108 }
2109
2110 /*!
2111  * This methods returns set of nodes in a newly allocated array that the caller has to deal with.
2112  * The returned nodes ids are those lying on the boundary of \b this.
2113  */
2114 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2115 {
2116   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> skin=computeSkin();
2117   return skin->computeFetchedNodeIds();
2118 }
2119
2120 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const throw(INTERP_KERNEL::Exception)
2121 {
2122   incrRef();
2123   return const_cast<MEDCouplingUMesh *>(this);
2124 }
2125
2126 /*
2127  * This method renumber 'this' using 'newNodeNumbers' array of size this->getNumberOfNodes.
2128  * newNbOfNodes specifies the *std::max_element(newNodeNumbers,newNodeNumbers+this->getNumberOfNodes())
2129  * This value is asked because often known by the caller of this method.
2130  * This method, contrary to MEDCouplingMesh::renumberCells does NOT conserve the number of nodes before and after.
2131  *
2132  * @param newNodeNumbers array specifying the new numbering in old2New convention.
2133  * @param newNbOfNodes the new number of nodes.
2134  */
2135 void MEDCouplingUMesh::renumberNodes(const int *newNodeNumbers, int newNbOfNodes)
2136 {
2137   MEDCouplingPointSet::renumberNodes(newNodeNumbers,newNbOfNodes);
2138   renumberNodesInConn(newNodeNumbers);
2139 }
2140
2141 /*
2142  * This method renumber 'this' using 'newNodeNumbers' array of size this->getNumberOfNodes.
2143  * newNbOfNodes specifies the *std::max_element(newNodeNumbers,newNodeNumbers+this->getNumberOfNodes())
2144  * This value is asked because often known by the caller of this method.
2145  * This method, contrary to MEDCouplingMesh::renumberCells does NOT conserve the number of nodes before and after.
2146  * The difference with ParaMEDMEM::MEDCouplingUMesh::renumberNodes method is in the fact that the barycenter of merged nodes is computed here.
2147  *
2148  * @param newNodeNumbers array specifying the new numbering.
2149  * @param newNbOfNodes the new number of nodes.
2150  *
2151  */
2152 void MEDCouplingUMesh::renumberNodes2(const int *newNodeNumbers, int newNbOfNodes)
2153 {
2154   MEDCouplingPointSet::renumberNodes2(newNodeNumbers,newNbOfNodes);
2155   renumberNodesInConn(newNodeNumbers);
2156 }
2157
2158 /*!
2159  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2160  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2161  * 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.
2162  * 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.
2163  * 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.
2164  *
2165  * \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
2166  *             parameter is altered during the call.
2167  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2168  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2169  * \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.
2170  *
2171  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2172  */
2173 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2174                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const throw(INTERP_KERNEL::Exception)
2175 {
2176   checkFullyDefined();
2177   otherDimM1OnSameCoords.checkFullyDefined();
2178   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2179     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2180   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2181     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2182   DataArrayInt *cellIdsRk0=0,*cellIdsRk1=0;
2183   findCellIdsLyingOn(otherDimM1OnSameCoords,cellIdsRk0,cellIdsRk1);
2184   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellIdsRk0Auto(cellIdsRk0),cellIdsRk1Auto(cellIdsRk1);
2185   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s0=cellIdsRk1->buildComplement(cellIdsRk0->getNumberOfTuples());
2186   s0->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2187   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0->begin(),s0->end(),true));
2188   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s1=m0Part->computeFetchedNodeIds();
2189   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s2=otherDimM1OnSameCoords.computeFetchedNodeIds();
2190   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> s3=s2->buildSubstraction(s1);
2191   cellIdsRk1->transformWithIndArr(cellIdsRk0Auto->begin(),cellIdsRk0Auto->end());
2192   //
2193   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellIdsRk1->begin(),cellIdsRk1->end(),true));
2194   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2195   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2196   DataArrayInt *idsTmp=0;
2197   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2198   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids(idsTmp);
2199   if(!b)
2200     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the given mdim-1 mesh in other is not a constituent of this !");
2201   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2202   DataArrayInt *tmp0=0,*tmp1=0;
2203   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2204   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neigh00(tmp0);
2205   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighI00(tmp1);
2206   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn0_torenum=MEDCouplingUMesh::ComputeSpreadZoneGradually(neigh00,neighI00);
2207   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2208   cellsToModifyConn0_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2209   cellsToModifyConn1_torenum->transformWithIndArr(cellIdsRk1->begin(),cellIdsRk1->end());
2210   //
2211   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum; cellsToModifyConn0_torenum->incrRef();
2212   cellIdsNotModified=cellsToModifyConn1_torenum; cellsToModifyConn1_torenum->incrRef();
2213   nodeIdsToDuplicate=s3; s3->incrRef();
2214 }
2215
2216 /*!
2217  * This method operates a modification of the connectivity and coords in \b this.
2218  * Every time that a node id in [\b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd) will append in nodal connectivity of \b this 
2219  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2220  * 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
2221  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2222  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2223  * 
2224  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2225  * 
2226  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2227  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2228  */
2229 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd) throw(INTERP_KERNEL::Exception)
2230 {
2231   int nbOfNodes=getNumberOfNodes();
2232   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2233   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2234 }
2235
2236 /*!
2237  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2238  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2239  * This method is an generalization of \ref ParaMEDMEM::MEDCouplingUMesh::shiftNodeNumbersInConn "shiftNodeNumbersInConn method".
2240  * @param [in] newNodeNumbers in old2New convention
2241  */
2242 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2243 {
2244   checkConnectivityFullyDefined();
2245   int *conn=getNodalConnectivity()->getPointer();
2246   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2247   int nbOfCells=getNumberOfCells();
2248   for(int i=0;i<nbOfCells;i++)
2249     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2250       {
2251         int& node=conn[iconn];
2252         if(node>=0)//avoid polyhedron separator
2253           {
2254             node=newNodeNumbersO2N[node];
2255           }
2256       }
2257   _nodal_connec->declareAsNew();
2258   updateTime();
2259 }
2260
2261 /*!
2262  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2263  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2264  * This method is an specialization of \ref ParaMEDMEM::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2265  * 
2266  * @param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2267  */
2268 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta) throw(INTERP_KERNEL::Exception)
2269 {
2270   checkConnectivityFullyDefined();
2271   int *conn=getNodalConnectivity()->getPointer();
2272   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2273   int nbOfCells=getNumberOfCells();
2274   for(int i=0;i<nbOfCells;i++)
2275     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2276       {
2277         int& node=conn[iconn];
2278         if(node>=0)//avoid polyhedron separator
2279           {
2280             node+=delta;
2281           }
2282       }
2283   _nodal_connec->declareAsNew();
2284   updateTime();
2285 }
2286
2287 /*!
2288  * This method operates a modification of the connectivity in \b this.
2289  * 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.
2290  * Every time that a node id in [\b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd) will append in nodal connectivity of \b this 
2291  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2292  * 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
2293  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2294  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2295  * 
2296  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2297  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2298  * 
2299  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2300  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2301  * \param [in] offset the offset applied to all node ids in connectivity that are in [nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd). 
2302  */
2303 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset) throw(INTERP_KERNEL::Exception)
2304 {
2305   checkConnectivityFullyDefined();
2306   std::map<int,int> m;
2307   int val=offset;
2308   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2309     m[*work]=val;
2310   int *conn=getNodalConnectivity()->getPointer();
2311   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2312   int nbOfCells=getNumberOfCells();
2313   for(int i=0;i<nbOfCells;i++)
2314     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2315       {
2316         int& node=conn[iconn];
2317         if(node>=0)//avoid polyhedron separator
2318           {
2319             std::map<int,int>::iterator it=m.find(node);
2320             if(it!=m.end())
2321               node=(*it).second;
2322           }
2323       }
2324   updateTime();
2325 }
2326
2327 /*!
2328  * This method renumbers cells of 'this' using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2329  *
2330  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2331  * After the call of this method the number of cells remains the same as before.
2332  *
2333  * If 'check' equals true the method will check that any elements in [old2NewBg;old2NewEnd) is unique ; if not
2334  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [old2NewBg;old2NewEnd) is not expected to
2335  * be strictly in [0;this->getNumberOfCells()).
2336  *
2337  * If 'check' equals false the method will not check the content of [old2NewBg;old2NewEnd).
2338  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [old2NewBg;old2NewEnd) should be unique and
2339  * should be contained in[0;this->getNumberOfCells()).
2340  * 
2341  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2342  */
2343 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check) throw(INTERP_KERNEL::Exception)
2344 {
2345   checkConnectivityFullyDefined();
2346   int nbCells=getNumberOfCells();
2347   const int *array=old2NewBg;
2348   if(check)
2349     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2350   //
2351   const int *conn=_nodal_connec->getConstPointer();
2352   const int *connI=_nodal_connec_index->getConstPointer();
2353   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
2354   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2355   newConn->copyStringInfoFrom(*_nodal_connec);
2356   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
2357   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2358   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2359   //
2360   int *newC=newConn->getPointer();
2361   int *newCI=newConnI->getPointer();
2362   int loc=0;
2363   newCI[0]=loc;
2364   for(int i=0;i<nbCells;i++)
2365     {
2366       std::size_t pos=std::distance(array,std::find(array,array+nbCells,i));
2367       int nbOfElts=connI[pos+1]-connI[pos];
2368       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2369       loc+=nbOfElts;
2370       newCI[i+1]=loc;
2371     }
2372   //
2373   setConnectivity(newConn,newConnI);
2374   if(check)
2375     delete [] const_cast<int *>(array);
2376 }
2377
2378 /*!
2379  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox'.
2380  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2381  * added in 'elems' parameter.
2382  */
2383 void MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps, std::vector<int>& elems) const
2384 {
2385   if(getMeshDimension()==-1)
2386     {
2387       elems.push_back(0);
2388       return;
2389     }
2390   int dim=getSpaceDimension();
2391   double* elem_bb=new double[2*dim];
2392   const int* conn      = getNodalConnectivity()->getConstPointer();
2393   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2394   const double* coords = getCoords()->getConstPointer();
2395   int nbOfCells=getNumberOfCells();
2396   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2397     {
2398       for (int i=0; i<dim; i++)
2399         {
2400           elem_bb[i*2]=std::numeric_limits<double>::max();
2401           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2402         }
2403
2404       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2405         {
2406           int node= conn[inode];
2407           if(node>=0)//avoid polyhedron separator
2408             {
2409               for (int idim=0; idim<dim; idim++)
2410                 {
2411                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2412                     {
2413                       elem_bb[idim*2] = coords[node*dim+idim] ;
2414                     }
2415                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2416                     {
2417                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2418                     }
2419                 }
2420             }
2421         }
2422       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2423         {
2424           elems.push_back(ielem);
2425         }
2426     }
2427   delete [] elem_bb;
2428 }
2429
2430 /*!
2431  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2432  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2433  * added in 'elems' parameter.
2434  */
2435 void MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps, std::vector<int>& elems)
2436 {
2437   if(getMeshDimension()==-1)
2438     {
2439       elems.push_back(0);
2440       return;
2441     }
2442   int dim=getSpaceDimension();
2443   double* elem_bb=new double[2*dim];
2444   const int* conn      = getNodalConnectivity()->getConstPointer();
2445   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2446   const double* coords = getCoords()->getConstPointer();
2447   int nbOfCells=getNumberOfCells();
2448   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2449     {
2450       for (int i=0; i<dim; i++)
2451         {
2452           elem_bb[i*2]=std::numeric_limits<double>::max();
2453           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2454         }
2455
2456       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2457         {
2458           int node= conn[inode];
2459           if(node>=0)//avoid polyhedron separator
2460             {
2461               for (int idim=0; idim<dim; idim++)
2462                 {
2463                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2464                     {
2465                       elem_bb[idim*2] = coords[node*dim+idim] ;
2466                     }
2467                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2468                     {
2469                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2470                     }
2471                 }
2472             }
2473         }
2474       if (intersectsBoundingBox(bbox, elem_bb, dim, eps))
2475         {
2476           elems.push_back(ielem);
2477         }
2478     }
2479   delete [] elem_bb;
2480 }
2481
2482 /*!
2483  * Returns the cell type of cell with id 'cellId'.
2484  */
2485 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2486 {
2487   const int *ptI=_nodal_connec_index->getConstPointer();
2488   const int *pt=_nodal_connec->getConstPointer();
2489   return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2490 }
2491
2492 /*!
2493  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2494  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2495  * The coordinates array is not considered here.
2496  *
2497  * \param [in] type the geometric type
2498  * \return the 
2499  */
2500 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const throw(INTERP_KERNEL::Exception)
2501 {
2502   
2503   std::vector<int> v;
2504   checkConnectivityFullyDefined();
2505   int nbCells=getNumberOfCells();
2506   int mdim=getMeshDimension();
2507   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2508   if(mdim!=(int)cm.getDimension())
2509     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2510   const int *ptI=_nodal_connec_index->getConstPointer();
2511   const int *pt=_nodal_connec->getConstPointer();
2512   for(int i=0;i<nbCells;i++)
2513     {
2514       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2515         v.push_back(i);
2516     }
2517   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc((int)v.size(),1);
2518   std::copy(v.begin(),v.end(),ret->getPointer());
2519   ret->incrRef();
2520   return ret;
2521 }
2522
2523 /*!
2524  * Returns nb of cells having the geometric type 'type'.
2525  */
2526 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2527 {
2528   const int *ptI=_nodal_connec_index->getConstPointer();
2529   const int *pt=_nodal_connec->getConstPointer();
2530   int nbOfCells=getNumberOfCells();
2531   int ret=0;
2532   for(int i=0;i<nbOfCells;i++)
2533     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2534       ret++;
2535   return ret;
2536 }
2537
2538 /*!
2539  * Appends the nodal connectivity in 'conn' of cell with id 'cellId'.
2540  * All elements added in conn can be used by MEDCouplingUMesh::getCoordinatesOfNode method.
2541  * That is to say -1 separator is omitted in returned conn.
2542  */
2543 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2544 {
2545   const int *ptI=_nodal_connec_index->getConstPointer();
2546   const int *pt=_nodal_connec->getConstPointer();
2547   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2548     if(*w>=0)
2549       conn.push_back(*w);
2550 }
2551
2552 std::string MEDCouplingUMesh::simpleRepr() const
2553 {
2554   static const char msg0[]="No coordinates specified !";
2555   std::ostringstream ret;
2556   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2557   ret << "Description of mesh : \"" << getDescription() << "\"\n";
2558   int tmpp1,tmpp2;
2559   double tt=getTime(tmpp1,tmpp2);
2560   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2561   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
2562   ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : ";
2563   if(_coords!=0)
2564     {
2565       const int spaceDim=getSpaceDimension();
2566       ret << spaceDim << "\nInfo attached on space dimension : ";
2567       for(int i=0;i<spaceDim;i++)
2568         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2569       ret << "\n";
2570     }
2571   else
2572     ret << msg0 << "\n";
2573   ret << "Number of nodes : ";
2574   if(_coords!=0)
2575     ret << getNumberOfNodes() << "\n";
2576   else
2577     ret << msg0 << "\n";
2578   ret << "Number of cells : ";
2579   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2580     ret << getNumberOfCells() << "\n";
2581   else
2582     ret << "No connectivity specified !" << "\n";
2583   ret << "Cell types present : ";
2584   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2585     {
2586       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2587       ret << cm.getRepr() << " ";
2588     }
2589   ret << "\n";
2590   return ret.str();
2591 }
2592
2593 std::string MEDCouplingUMesh::advancedRepr() const
2594 {
2595   std::ostringstream ret;
2596   ret << simpleRepr();
2597   ret << "\nCoordinates array : \n___________________\n\n";
2598   if(_coords)
2599     _coords->reprWithoutNameStream(ret);
2600   else
2601     ret << "No array set !\n";
2602   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2603   reprConnectivityOfThisLL(ret);
2604   return ret.str();
2605 }
2606
2607 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2608 {
2609   std::ostringstream ret;
2610   reprConnectivityOfThisLL(ret);
2611   return ret.str();
2612 }
2613
2614 /*!
2615  * This method builds a newly allocated instance (with the same name than 'this') that the caller has the responsability to deal with.
2616  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2617  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2618  * some algos).
2619  * 
2620  * This method expects that 'this' has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2621  * 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
2622  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2623  */
2624 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const throw(INTERP_KERNEL::Exception)
2625 {
2626   int mdim=getMeshDimension();
2627   if(mdim<0)
2628     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2629   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2630   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1,tmp2;
2631   bool needToCpyCT=true;
2632   if(!_nodal_connec)
2633     {
2634       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
2635       needToCpyCT=false;
2636     }
2637   else
2638     {
2639       tmp1=_nodal_connec;
2640       tmp1->incrRef();
2641     }
2642   if(!_nodal_connec_index)
2643     {
2644       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2645       needToCpyCT=false;
2646     }
2647   else
2648     {
2649       tmp2=_nodal_connec_index;
2650       tmp2->incrRef();
2651     }
2652   ret->setConnectivity(tmp1,tmp2,false);
2653   if(needToCpyCT)
2654     ret->_types=_types;
2655   if(!_coords)
2656     {
2657       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2658       ret->setCoords(coords);
2659     }
2660   else
2661     ret->setCoords(_coords);
2662   ret->incrRef();
2663   return ret;
2664 }
2665
2666 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
2667 {
2668   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2669     {
2670       int nbOfCells=getNumberOfCells();
2671       const int *c=_nodal_connec->getConstPointer();
2672       const int *ci=_nodal_connec_index->getConstPointer();
2673       for(int i=0;i<nbOfCells;i++)
2674         {
2675           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
2676           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
2677           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
2678           stream << "\n";
2679         }
2680     }
2681   else
2682     stream << "Connectivity not defined !\n";
2683 }
2684
2685 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
2686 {
2687   const int *ptI=_nodal_connec_index->getConstPointer();
2688   const int *pt=_nodal_connec->getConstPointer();
2689   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
2690     return ptI[cellId+1]-ptI[cellId]-1;
2691   else
2692     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
2693 }
2694
2695 /*!
2696  * This method is equivalent to MEDCouplingUMesh::getAllTypes excecpt that it returns only types of submesh which cell ids are in [begin,end).
2697  * This method avoids to compute explicitely submesh to get its types.
2698  */
2699 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const throw(INTERP_KERNEL::Exception)
2700 {
2701   checkFullyDefined();
2702   std::set<INTERP_KERNEL::NormalizedCellType> ret;
2703   const int *conn=_nodal_connec->getConstPointer();
2704   const int *connIndex=_nodal_connec_index->getConstPointer();
2705   for(const int *w=begin;w!=end;w++)
2706     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
2707   return ret;
2708 }
2709
2710 /*!
2711  * Method reserved for advanced users having prepared their connectivity before.
2712  * Arrays 'conn' and 'connIndex' will be aggregated without any copy and their counter will be incremented.
2713  */
2714 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
2715 {
2716   DataArrayInt::SetArrayIn(conn,_nodal_connec);
2717   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
2718   if(isComputingTypes)
2719     computeTypes();
2720   declareAsNew();
2721 }
2722
2723 /*!
2724  * Copy constructor. If 'deepCpy' is false 'this' is a shallow copy of other.
2725  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
2726  */
2727 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_iterator(-1),_mesh_dim(other._mesh_dim),
2728                                                                                  _nodal_connec(0),_nodal_connec_index(0),
2729                                                                                 _types(other._types)
2730 {
2731   if(other._nodal_connec)
2732     _nodal_connec=other._nodal_connec->performCpy(deepCopy);
2733   if(other._nodal_connec_index)
2734     _nodal_connec_index=other._nodal_connec_index->performCpy(deepCopy);
2735 }
2736
2737 MEDCouplingUMesh::~MEDCouplingUMesh()
2738 {
2739   if(_nodal_connec)
2740     _nodal_connec->decrRef();
2741   if(_nodal_connec_index)
2742     _nodal_connec_index->decrRef();
2743 }
2744
2745 /*!
2746  * This method recomputes all cell types of 'this'.
2747  */
2748 void MEDCouplingUMesh::computeTypes()
2749 {
2750   if(_nodal_connec && _nodal_connec_index)
2751     {
2752       _types.clear();
2753       const int *conn=_nodal_connec->getConstPointer();
2754       const int *connIndex=_nodal_connec_index->getConstPointer();
2755       int nbOfElem=_nodal_connec_index->getNbOfElems()-1;
2756       for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
2757         _types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
2758     }
2759 }
2760
2761 /*!
2762  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
2763  */
2764 void MEDCouplingUMesh::checkFullyDefined() const throw(INTERP_KERNEL::Exception)
2765 {
2766   if(!_nodal_connec_index || !_nodal_connec || !_coords)
2767     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
2768 }
2769
2770 /*!
2771  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
2772  */
2773 void MEDCouplingUMesh::checkConnectivityFullyDefined() const throw(INTERP_KERNEL::Exception)
2774 {
2775   if(!_nodal_connec_index || !_nodal_connec)
2776     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
2777 }
2778
2779 int MEDCouplingUMesh::getNumberOfCells() const
2780
2781   if(_nodal_connec_index)
2782     if(_iterator==-1)
2783       return _nodal_connec_index->getNumberOfTuples()-1;
2784     else
2785       return _iterator;
2786   else
2787     if(_mesh_dim==-1)
2788       return 1;
2789     else
2790       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
2791 }
2792
2793 int MEDCouplingUMesh::getMeshDimension() const
2794 {
2795   if(_mesh_dim<-1)
2796     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
2797   return _mesh_dim;
2798 }
2799
2800 /*!
2801  * This method is for test reason. Normally the integer returned is not useable by user.
2802  */
2803 int MEDCouplingUMesh::getMeshLength() const
2804 {
2805   return _nodal_connec->getNbOfElems();
2806 }
2807
2808 /*!
2809  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
2810  */
2811 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
2812 {
2813   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
2814   tinyInfo.push_back(getMeshDimension());
2815   tinyInfo.push_back(getNumberOfCells());
2816   if(_nodal_connec)
2817     tinyInfo.push_back(getMeshLength());
2818   else
2819     tinyInfo.push_back(-1);
2820 }
2821
2822 /*!
2823  * First step of unserialization process.
2824  */
2825 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
2826 {
2827   return tinyInfo[6]<=0;
2828 }
2829
2830 /*!
2831  * Second step of serialization process.
2832  * @param tinyInfo must be equal to the result given by getTinySerializationInformation method.
2833  */
2834 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
2835 {
2836   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
2837   if(tinyInfo[5]!=-1)
2838     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
2839 }
2840
2841 /*!
2842  * Third and final step of serialization process.
2843  */
2844 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
2845 {
2846   MEDCouplingPointSet::serialize(a1,a2);
2847   if(getMeshDimension()>-1)
2848     {
2849       a1=DataArrayInt::New();
2850       a1->alloc(getMeshLength()+getNumberOfCells()+1,1);
2851       int *ptA1=a1->getPointer();
2852       const int *conn=getNodalConnectivity()->getConstPointer();
2853       const int *index=getNodalConnectivityIndex()->getConstPointer();
2854       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
2855       std::copy(conn,conn+getMeshLength(),ptA1);
2856     }
2857   else
2858     a1=0;
2859 }
2860
2861 /*!
2862  * Second and final unserialization process.
2863  * @param tinyInfo must be equal to the result given by getTinySerializationInformation method.
2864  */
2865 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
2866 {
2867   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
2868   setMeshDimension(tinyInfo[5]);
2869   if(tinyInfo[7]!=-1)
2870     {
2871       // Connectivity
2872       const int *recvBuffer=a1->getConstPointer();
2873       DataArrayInt* myConnecIndex=DataArrayInt::New();
2874       myConnecIndex->alloc(tinyInfo[6]+1,1);
2875       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
2876       DataArrayInt* myConnec=DataArrayInt::New();
2877       myConnec->alloc(tinyInfo[7],1);
2878       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
2879       setConnectivity(myConnec, myConnecIndex) ;
2880       myConnec->decrRef();
2881       myConnecIndex->decrRef();
2882     }
2883 }
2884
2885 /*!
2886  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf2.
2887  * CellIds are given using range specified by a start an end and step.
2888  */
2889 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords2(int start, int end, int step) const
2890 {
2891   checkFullyDefined();
2892   int ncell=getNumberOfCells();
2893   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2894   ret->_mesh_dim=_mesh_dim;
2895   ret->setCoords(_coords);
2896   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : ");
2897   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
2898   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
2899   int work=start;
2900   const int *conn=_nodal_connec->getConstPointer();
2901   const int *connIndex=_nodal_connec_index->getConstPointer();
2902   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
2903     {
2904       if(work>=0 && work<ncell)
2905         {
2906           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
2907         }
2908       else
2909         {
2910           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords2 : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
2911           throw INTERP_KERNEL::Exception(oss.str().c_str());
2912         }
2913     }
2914   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
2915   int *newConnPtr=newConn->getPointer();
2916   std::set<INTERP_KERNEL::NormalizedCellType> types;
2917   work=start;
2918   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
2919     {
2920       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
2921       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
2922     }
2923   ret->setConnectivity(newConn,newConnI,false);
2924   ret->_types=types;
2925   ret->copyTinyInfoFrom(this);
2926   std::string name(getName());
2927   std::size_t sz=strlen(PART_OF_NAME);
2928   if(name.length()>=sz)
2929     name=name.substr(0,sz);
2930   if(name!=PART_OF_NAME)
2931     {
2932       std::ostringstream stream; stream << PART_OF_NAME << getName();
2933       ret->setName(stream.str().c_str());
2934     }
2935   else
2936     ret->setName(getName());
2937   ret->incrRef();
2938   return ret;
2939 }
2940
2941 /*!
2942  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
2943  * Keeps from 'this' only cells which constituing point id are in the ids specified by ['begin','end').
2944  * The return newly allocated mesh will share the same coordinates as 'this'.
2945  */
2946 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
2947 {
2948   checkFullyDefined();
2949   int ncell=getNumberOfCells();
2950   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
2951   ret->_mesh_dim=_mesh_dim;
2952   ret->setCoords(_coords);
2953   std::size_t nbOfElemsRet=std::distance(begin,end);
2954   int *connIndexRet=new int[nbOfElemsRet+1];
2955   connIndexRet[0]=0;
2956   const int *conn=_nodal_connec->getConstPointer();
2957   const int *connIndex=_nodal_connec_index->getConstPointer();
2958   int newNbring=0;
2959   for(const int *work=begin;work!=end;work++,newNbring++)
2960     {
2961       if(*work>=0 && *work<ncell)
2962         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
2963       else
2964         {
2965           delete [] connIndexRet;
2966           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
2967           throw INTERP_KERNEL::Exception(oss.str().c_str());
2968         }
2969     }
2970   int *connRet=new int[connIndexRet[nbOfElemsRet]];
2971   int *connRetWork=connRet;
2972   std::set<INTERP_KERNEL::NormalizedCellType> types;
2973   for(const int *work=begin;work!=end;work++)
2974     {
2975       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
2976       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
2977     }
2978   DataArrayInt *connRetArr=DataArrayInt::New();
2979   connRetArr->useArray(connRet,true,CPP_DEALLOC,connIndexRet[nbOfElemsRet],1);
2980   DataArrayInt *connIndexRetArr=DataArrayInt::New();
2981   connIndexRetArr->useArray(connIndexRet,true,CPP_DEALLOC,(int)nbOfElemsRet+1,1);
2982   ret->setConnectivity(connRetArr,connIndexRetArr,false);
2983   ret->_types=types;
2984   connRetArr->decrRef();
2985   connIndexRetArr->decrRef();
2986   ret->copyTinyInfoFrom(this);
2987   std::string name(getName());
2988   std::size_t sz=strlen(PART_OF_NAME);
2989   if(name.length()>=sz)
2990     name=name.substr(0,sz);
2991   if(name!=PART_OF_NAME)
2992     {
2993       std::ostringstream stream; stream << PART_OF_NAME << getName();
2994       ret->setName(stream.str().c_str());
2995     }
2996   else
2997     ret->setName(getName());
2998   ret->incrRef();
2999   return ret;
3000 }
3001
3002 /*!
3003  * brief returns the volumes of the cells underlying the field \a field
3004  *
3005  * For 2D geometries, the returned field contains the areas.
3006  * For 3D geometries, the returned field contains the volumes.
3007  *
3008  * param field field on which cells the volumes are required
3009  * return field containing the volumes, area or length depending the meshdimension.
3010  */
3011 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3012 {
3013   std::string name="MeasureOfMesh_";
3014   name+=getName();
3015   int nbelem=getNumberOfCells();
3016   MEDCouplingFieldDouble *field=MEDCouplingFieldDouble::New(ON_CELLS);
3017   field->setName(name.c_str());
3018   DataArrayDouble* array=DataArrayDouble::New();
3019   array->alloc(nbelem,1);
3020   double *area_vol=array->getPointer();
3021   field->setArray(array) ;
3022   array->decrRef();
3023   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3024   if(getMeshDimension()!=-1)
3025     {
3026       int ipt;
3027       INTERP_KERNEL::NormalizedCellType type;
3028       int dim_space=getSpaceDimension();
3029       const double *coords=getCoords()->getConstPointer();
3030       const int *connec=getNodalConnectivity()->getConstPointer();
3031       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3032       for(int iel=0;iel<nbelem;iel++)
3033         {
3034           ipt=connec_index[iel];
3035           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3036           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);
3037         }
3038       if(isAbs)
3039         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3040     }
3041   else
3042     {
3043       area_vol[0]=std::numeric_limits<double>::max();
3044     }
3045   return field;
3046 }
3047
3048 /*!
3049  * This method is equivalent to MEDCouplingUMesh::getMeasureField except that only part defined by [begin,end) is returned !
3050  * This method avoids to build explicitely part of this to perform the work.
3051  */
3052 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3053 {
3054   std::string name="PartMeasureOfMesh_";
3055   name+=getName();
3056   int nbelem=(int)std::distance(begin,end);
3057   DataArrayDouble* array=DataArrayDouble::New();
3058   array->setName(name.c_str());
3059   array->alloc(nbelem,1);
3060   double *area_vol=array->getPointer();
3061   if(getMeshDimension()!=-1)
3062     {
3063       int ipt;
3064       INTERP_KERNEL::NormalizedCellType type;
3065       int dim_space=getSpaceDimension();
3066       const double *coords=getCoords()->getConstPointer();
3067       const int *connec=getNodalConnectivity()->getConstPointer();
3068       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3069       for(const int *iel=begin;iel!=end;iel++)
3070         {
3071           ipt=connec_index[*iel];
3072           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3073           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3074         }
3075       if(isAbs)
3076         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3077     }
3078   else
3079     {
3080       area_vol[0]=std::numeric_limits<double>::max();
3081     }
3082   return array;
3083 }
3084
3085 /*!
3086  * This methods returns a field on nodes and no time. This method is usefull to check "P1*" conservative interpolators.
3087  * This field returns the getMeasureField of the dualMesh in P1 sens of 'this'.
3088  */
3089 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3090 {
3091   MEDCouplingFieldDouble *tmp=getMeasureField(isAbs);
3092   std::string name="MeasureOnNodeOfMesh_";
3093   name+=getName();
3094   int nbNodes=getNumberOfNodes();
3095   MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_NODES);
3096   double cst=1./((double)getMeshDimension()+1.);
3097   DataArrayDouble* array=DataArrayDouble::New();
3098   array->alloc(nbNodes,1);
3099   double *valsToFill=array->getPointer();
3100   std::fill(valsToFill,valsToFill+nbNodes,0.);
3101   const double *values=tmp->getArray()->getConstPointer();
3102   DataArrayInt *da=DataArrayInt::New();
3103   DataArrayInt *daInd=DataArrayInt::New();
3104   getReverseNodalConnectivity(da,daInd);
3105   const int *daPtr=da->getConstPointer();
3106   const int *daIPtr=daInd->getConstPointer();
3107   for(int i=0;i<nbNodes;i++)
3108     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3109       valsToFill[i]+=cst*values[*cell];
3110   ret->setMesh(this);
3111   da->decrRef();
3112   daInd->decrRef();
3113   ret->setArray(array);
3114   array->decrRef();
3115   tmp->decrRef();
3116   return ret;
3117 }
3118
3119 /*!
3120  * This methods returns a vector field on cells that represents the orthogonal vector normalized of each 2D cell of this.
3121  * This method is only callable on mesh with meshdim == 2 and spacedim==2 or 3.
3122  */
3123 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3124 {
3125   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3126     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3127   MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
3128   DataArrayDouble *array=DataArrayDouble::New();
3129   int nbOfCells=getNumberOfCells();
3130   int nbComp=getMeshDimension()+1;
3131   array->alloc(nbOfCells,nbComp);
3132   double *vals=array->getPointer();
3133   const int *connI=_nodal_connec_index->getConstPointer();
3134   const int *conn=_nodal_connec->getConstPointer();
3135   const double *coords=_coords->getConstPointer();
3136   if(getMeshDimension()==2)
3137     {
3138       if(getSpaceDimension()==3)
3139         {
3140           DataArrayDouble *loc=getBarycenterAndOwner();
3141           const double *locPtr=loc->getConstPointer();
3142           for(int i=0;i<nbOfCells;i++,vals+=3)
3143             {
3144               int offset=connI[i];
3145               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3146               double n=INTERP_KERNEL::norm<3>(vals);
3147               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3148             }
3149           loc->decrRef();
3150         }
3151       else
3152         {
3153           for(int i=0;i<nbOfCells;i++)
3154             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3155         }
3156     }
3157   else//meshdimension==1
3158     {
3159       double tmp[2];
3160       for(int i=0;i<nbOfCells;i++)
3161         {
3162           int offset=connI[i];
3163           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3164           double n=INTERP_KERNEL::norm<2>(tmp);
3165           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3166           *vals++=-tmp[1];
3167           *vals++=tmp[0];
3168         }
3169     }
3170   ret->setArray(array);
3171   array->decrRef();
3172   ret->setMesh(this);
3173   return ret;
3174 }
3175
3176 /*!
3177  * This method is equivalent to MEDCouplingUMesh::buildOrthogonalField except that only part defined by [begin,end) is returned !
3178  * This method avoids to build explicitely part of this to perform the work.
3179  */
3180 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3181 {
3182   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3183     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3184   MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
3185   DataArrayDouble *array=DataArrayDouble::New();
3186   std::size_t nbelems=std::distance(begin,end);
3187   int nbComp=getMeshDimension()+1;
3188   array->alloc((int)nbelems,nbComp);
3189   double *vals=array->getPointer();
3190   const int *connI=_nodal_connec_index->getConstPointer();
3191   const int *conn=_nodal_connec->getConstPointer();
3192   const double *coords=_coords->getConstPointer();
3193   if(getMeshDimension()==2)
3194     {
3195       if(getSpaceDimension()==3)
3196         {
3197           DataArrayDouble *loc=getPartBarycenterAndOwner(begin,end);
3198           const double *locPtr=loc->getConstPointer();
3199           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3200             {
3201               int offset=connI[*i];
3202               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3203               double n=INTERP_KERNEL::norm<3>(vals);
3204               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3205             }
3206           loc->decrRef();
3207         }
3208       else
3209         {
3210           for(std::size_t i=0;i<nbelems;i++)
3211             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3212         }
3213     }
3214   else//meshdimension==1
3215     {
3216       double tmp[2];
3217       for(const int *i=begin;i!=end;i++)
3218         {
3219           int offset=connI[*i];
3220           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3221           double n=INTERP_KERNEL::norm<2>(tmp);
3222           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3223           *vals++=-tmp[1];
3224           *vals++=tmp[0];
3225         }
3226     }
3227   ret->setArray(array);
3228   array->decrRef();
3229   ret->setMesh(this);
3230   return ret;
3231 }
3232
3233 /*!
3234  * This methods returns a vector newly created field on cells that represents the direction vector of each 1D cell of this.
3235  * This method is only callable on mesh with meshdim == 1 containing only SEG2.
3236  */
3237 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3238 {
3239    if(getMeshDimension()!=1)
3240     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3241    if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3242      throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3243    MEDCouplingFieldDouble *ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
3244    DataArrayDouble *array=DataArrayDouble::New();
3245    int nbOfCells=getNumberOfCells();
3246    int spaceDim=getSpaceDimension();
3247    array->alloc(nbOfCells,spaceDim);
3248    double *pt=array->getPointer();
3249    const double *coo=getCoords()->getConstPointer();
3250    std::vector<int> conn;
3251    conn.reserve(2);
3252    for(int i=0;i<nbOfCells;i++)
3253      {
3254        conn.resize(0);
3255        getNodeIdsOfCell(i,conn);
3256        pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3257      }
3258    ret->setArray(array);
3259    array->decrRef();
3260    ret->setMesh(this);
3261    return ret;   
3262 }
3263
3264 /*!
3265  * 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.
3266  * This method returns 2 objects : 
3267  * - a newly created mesh instance containing the result of the slice lying on different coords than 'this' and with a meshdim == 2
3268  * - 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
3269  *   mesh the 3D cell id is 'this' it comes from.
3270  * This method works only for linear meshes (non quadratic).
3271  * 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
3272  * face. Only 'cellIds' parameter can distinguish the 2.
3273  * @param origin is the origin of the plane. It should be an array of length 3.
3274  * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3275  * @param eps is the precision. It is used by called method MEDCouplingUMesh::getCellIdsCrossingPlane for the first 3D cell selection (in absolute). 'eps' is
3276  * 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).
3277  */
3278 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const throw(INTERP_KERNEL::Exception)
3279 {
3280   checkFullyDefined();
3281   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3282     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3283   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3284   if(candidates->empty())
3285     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3286   std::vector<int> nodes;
3287   std::vector<int> cellIds2D,cellIds1D;
3288   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3289   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3290   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3291   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3292   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3293   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3294   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3295   revDesc2=0; revDescIndx2=0;
3296   mDesc2->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds2D);
3297   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3298   revDesc1=0; revDescIndx1=0;
3299   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3300   //
3301   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3302   for(std::vector<int>::const_iterator it=cellIds1D.begin();it!=cellIds1D.end();it++)
3303     cut3DCurve[*it]=-1;
3304   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3305   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3306   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3307                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3308                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3309   std::vector<int> conn,connI,cellIds2;
3310   connI.push_back(0);
3311   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3312   if(cellIds2.empty())
3313     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3314   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3315   ret->setCoords(mDesc1->getCoords());
3316   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
3317   c->alloc((int)conn.size(),1); std::copy(conn.begin(),conn.end(),c->getPointer());
3318   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
3319   cI->alloc((int)connI.size(),1); std::copy(connI.begin(),connI.end(),cI->getPointer());
3320   ret->setConnectivity(c,cI,true);
3321   cellIds=candidates->selectByTupleId(&cellIds2[0],&cellIds2[0]+cellIds2.size());
3322   ret->incrRef();
3323   return ret;
3324 }
3325
3326 /*!
3327  * 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.
3328  * This method returns 2 objects : 
3329  * - a newly created mesh instance containing the result of the slice lying on different coords than 'this' and with a meshdim == 1
3330  * - 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
3331  *   mesh the 3DSurf cell id is 'this' it comes from.
3332  * This method works only for linear meshes (non quadratic).
3333  * 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
3334  * face. Only 'cellIds' parameter can distinguish the 2.
3335  * @param origin is the origin of the plane. It should be an array of length 3.
3336  * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3337  * @param eps is the precision. It is used by called method MEDCouplingUMesh::getCellIdsCrossingPlane for the first 3DSurf cell selection (in absolute). 'eps' is
3338  * 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).
3339  */
3340 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const throw(INTERP_KERNEL::Exception)
3341 {
3342   checkFullyDefined();
3343   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3344     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3345   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3346   if(candidates->empty())
3347     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3348   std::vector<int> nodes;
3349   std::vector<int> cellIds1D;
3350   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3351   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3352   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New();
3353   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New();
3354   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New();
3355   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New();
3356   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3357   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3358   //
3359   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3360   for(std::vector<int>::const_iterator it=cellIds1D.begin();it!=cellIds1D.end();it++)
3361     cut3DCurve[*it]=-1;
3362   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3363   int ncellsSub=subMesh->getNumberOfCells();
3364   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3365   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3366                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3367                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3368   std::vector<int> conn,connI,cellIds2; connI.push_back(0);
3369   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3370   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3371   for(int i=0;i<ncellsSub;i++)
3372     {
3373       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3374         {
3375           if(cut3DSurf[i].first!=-2)
3376             {
3377               conn.push_back((int)INTERP_KERNEL::NORM_SEG2); conn.push_back(cut3DSurf[i].first); conn.push_back(cut3DSurf[i].second);
3378               connI.push_back((int)conn.size());
3379               cellIds2.push_back(i);
3380             }
3381           else
3382             {
3383               int cellId3DSurf=cut3DSurf[i].second;
3384               int offset=nodalI[cellId3DSurf]+1;
3385               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3386               for(int j=0;j<nbOfEdges;j++)
3387                 {
3388                   conn.push_back((int)INTERP_KERNEL::NORM_SEG2); conn.push_back(nodal[offset+j]); conn.push_back(nodal[offset+(j+1)%nbOfEdges]);
3389                   connI.push_back((int)conn.size());
3390                   cellIds2.push_back(cellId3DSurf);
3391                 }
3392             }
3393         }
3394     }
3395   if(cellIds2.empty())
3396     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3397   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3398   ret->setCoords(mDesc1->getCoords());
3399   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
3400   c->alloc((int)conn.size(),1); std::copy(conn.begin(),conn.end(),c->getPointer());
3401   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
3402   cI->alloc((int)connI.size(),1); std::copy(connI.begin(),connI.end(),cI->getPointer());
3403   ret->setConnectivity(c,cI,true);
3404   cellIds=candidates->selectByTupleId(&cellIds2[0],&cellIds2[0]+cellIds2.size());
3405   ret->incrRef();
3406   return ret;
3407 }
3408
3409 /*!
3410  * This method expects that 'this' is fully defined and has a spaceDim==3. If it is not the case an exception will be thrown.
3411  * This method returns a newly created dataarray containing cellsids in 'this' that potentially crosses the plane specified by 'origin' and 'vec'.
3412  * @param origin is the origin of the plane. It should be an array of length 3.
3413  * @param vec is the direction vector of the plane. It should be an array of length 3. Norm of 'vec' should be > 1e-6.
3414  */
3415 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const throw(INTERP_KERNEL::Exception)
3416 {
3417   checkFullyDefined();
3418   if(getSpaceDimension()!=3)
3419     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3420   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3421   if(normm<1e-6)
3422     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3423   double vec2[3];
3424   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3425   double angle=acos(vec[2]/normm);
3426   std::vector<int> cellIds;
3427   double bbox[6];
3428   if(angle>eps)
3429     {
3430       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=_coords->deepCpy();
3431       MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3432       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3433       mw->setCoords(coo);
3434       mw->getBoundingBox(bbox);
3435       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3436       mw->getCellsInBoundingBox(bbox,eps,cellIds);
3437     }
3438   else
3439     {
3440       getBoundingBox(bbox);
3441       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3442       getCellsInBoundingBox(bbox,eps,cellIds);
3443     }
3444   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
3445   ret->alloc((int)cellIds.size(),1);
3446   std::copy(cellIds.begin(),cellIds.end(),ret->getPointer());
3447   ret->incrRef();
3448   return ret;
3449 }
3450
3451 /*!
3452  * This method checks that 'this' is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3453  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3454  * No consideration of coordinate is done by this method.
3455  * 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)
3456  * If not false is returned. In case that false is returned a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes could be usefull.
3457  */
3458 bool MEDCouplingUMesh::isContiguous1D() const throw(INTERP_KERNEL::Exception)
3459 {
3460   if(getMeshDimension()!=1)
3461     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3462   int nbCells=getNumberOfCells();
3463   if(nbCells<1)
3464     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3465   const int *connI=_nodal_connec_index->getConstPointer();
3466   const int *conn=_nodal_connec->getConstPointer();
3467   int ref=conn[connI[0]+2];
3468   for(int i=1;i<nbCells;i++)
3469     {
3470       if(conn[connI[i]+1]!=ref)
3471         return false;
3472       ref=conn[connI[i]+2];
3473     }
3474   return true;
3475 }
3476
3477 /*!
3478  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3479  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3480  * @param pt reference point of the line
3481  * @param v normalized director vector of the line
3482  * @param eps max precision before throwing an exception
3483  * @param res output of size this->getNumberOfCells
3484  */
3485 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3486 {
3487   if(getMeshDimension()!=1)
3488     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3489    if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3490      throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3491    if(getSpaceDimension()!=3)
3492      throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3493    MEDCouplingFieldDouble *f=buildDirectionVectorField();
3494    const double *fPtr=f->getArray()->getConstPointer();
3495    double tmp[3];
3496    for(int i=0;i<getNumberOfCells();i++)
3497      {
3498        const double *tmp1=fPtr+3*i;
3499        tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3500        tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3501        tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3502        double n1=INTERP_KERNEL::norm<3>(tmp);
3503        n1/=INTERP_KERNEL::norm<3>(tmp1);
3504        if(n1>eps)
3505          {
3506            f->decrRef();
3507            throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3508          }
3509      }
3510    const double *coo=getCoords()->getConstPointer();
3511    for(int i=0;i<getNumberOfNodes();i++)
3512      {
3513        std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3514        std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3515        res[i]=std::accumulate(tmp,tmp+3,0.);
3516      }
3517    f->decrRef();
3518 }
3519
3520 /*!
3521  * Returns a cell if any that contains the point located on 'pos' with precison eps.
3522  * If 'pos' is outside 'this' -1 is returned. If several cells contain this point the cell with the smallest id is returned.
3523  * \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'
3524  * it is better to use MEDCouplingUMesh::getCellsContainingPoints method because in this case, the acceleration structure will be computed only once.
3525  */
3526 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
3527 {
3528   std::vector<int> elts;
3529   getCellsContainingPoint(pos,eps,elts);
3530   if(elts.empty())
3531     return -1;
3532   return elts.front();
3533 }
3534
3535 /*!
3536  * Returns all cellIds in 'elts' of point 'pos' with eps accuracy.
3537  * \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'
3538  * it is better to use MEDCouplingUMesh::getCellsContainingPoints method because in this case, the acceleration structure will be computed only once.
3539  */
3540 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
3541 {
3542   std::vector<int> eltsIndex;
3543   getCellsContainingPoints(pos,1,eps,elts,eltsIndex);
3544 }
3545
3546 /// @cond INTERNAL
3547
3548 namespace ParaMEDMEM
3549 {
3550   template<const int SPACEDIMM>
3551   class DummyClsMCUG
3552   {
3553   public:
3554     static const int MY_SPACEDIM=SPACEDIMM;
3555     static const int MY_MESHDIM=8;
3556     typedef int MyConnType;
3557     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
3558     // begin
3559     // useless, but for windows compilation ...
3560     const double* getCoordinatesPtr() const { return 0; }
3561     const int* getConnectivityPtr() const { return 0; }
3562     const int* getConnectivityIndexPtr() const { return 0; }
3563     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
3564     // end
3565   };
3566
3567   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
3568   {
3569     INTERP_KERNEL::Edge *ret=0;
3570     switch(typ)
3571       {
3572       case INTERP_KERNEL::NORM_SEG2:
3573         {
3574           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
3575           break;
3576         }
3577       case INTERP_KERNEL::NORM_SEG3:
3578         {
3579           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
3580           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
3581           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
3582           bool colinearity=inters.areColinears();
3583           delete e1; delete e2;
3584           if(colinearity)
3585             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
3586           else
3587             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
3588           mapp2[bg[2]].second=false;
3589           break;
3590         }
3591       default:
3592         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
3593       }
3594     return ret;
3595   }
3596
3597   /*!
3598    * 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'.
3599    * The input meth 'mDesc' must be so that mDim==1 et spaceDim==3.
3600    * 'mapp' contains a mapping between local numbering in submesh and the global node numbering in 'mDesc'.
3601    */
3602   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates, std::map<INTERP_KERNEL::Node *,int>& mapp) throw(INTERP_KERNEL::Exception)
3603   {
3604     mapp.clear();
3605     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.
3606     const double *coo=mDesc->getCoords()->getConstPointer();
3607     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
3608     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
3609     std::set<int> s;
3610     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
3611       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
3612     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
3613       {
3614         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
3615         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
3616       }
3617     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
3618     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
3619       {
3620         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
3621         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
3622       }
3623     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
3624       {
3625         if((*it2).second.second)
3626           mapp[(*it2).second.first]=(*it2).first;
3627         ((*it2).second.first)->decrRef();
3628       }
3629     return ret;
3630   }
3631
3632   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
3633   {
3634     if(nodeId>=offset2)
3635       {
3636         int locId=nodeId-offset2;
3637         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
3638       }
3639     if(nodeId>=offset1)
3640       {
3641         int locId=nodeId-offset1;
3642         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
3643       }
3644     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
3645   }
3646
3647   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
3648                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
3649                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
3650   {
3651     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
3652       {
3653         int eltId1=abs(*desc1)-1;
3654         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
3655           {
3656             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
3657             if(it==mappRev.end())
3658               {
3659                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
3660                 mapp[node]=*it1;
3661                 mappRev[*it1]=node;
3662               }
3663           }
3664       }
3665   }
3666 }
3667
3668 /// @endcond
3669
3670 template<int SPACEDIM>
3671 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
3672                                                    double eps, std::vector<int>& elts, std::vector<int>& eltsIndex) const
3673 {
3674   std::vector<double> bbox;
3675   eltsIndex.resize(nbOfPoints+1);
3676   eltsIndex[0]=0;
3677   elts.clear();
3678   getBoundingBoxForBBTree(bbox);
3679   int nbOfCells=getNumberOfCells();
3680   const int *conn=_nodal_connec->getConstPointer();
3681   const int *connI=_nodal_connec_index->getConstPointer();
3682   double bb[2*SPACEDIM];
3683   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
3684   for(int i=0;i<nbOfPoints;i++)
3685     {
3686       eltsIndex[i+1]=eltsIndex[i];
3687       for(int j=0;j<SPACEDIM;j++)
3688         {
3689           bb[2*j]=pos[SPACEDIM*i+j];
3690           bb[2*j+1]=pos[SPACEDIM*i+j];
3691         }
3692       std::vector<int> candidates;
3693       myTree.getIntersectingElems(bb,candidates);
3694       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
3695         {
3696           int sz=connI[(*iter)+1]-connI[*iter]-1;
3697           if(INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,
3698                                                                                                (INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]],
3699                                                                                                coords,conn+connI[*iter]+1,sz,eps))
3700             {
3701               eltsIndex[i+1]++;
3702               elts.push_back(*iter);
3703             }
3704         }
3705     }
3706 }
3707
3708 /*!
3709  * This method is an extension of MEDCouplingUMesh::getCellContainingPoint and MEDCouplingUMesh::getCellsContainingPoint.
3710  * This method performs 'nbOfPoints' time the getCellsContainingPoint request. This method is recommended rather than the 2 others
3711  * in case of multi points searching.
3712  * This method returns 2 arrays 'elts' and 'eltsIndex'. 'eltsIndex' is of size 'nbOfPoints+1' and 'elts' is of size 'eltsIndex[nbOfPoints-1]'.
3713  * 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]).
3714  * 
3715  * \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...
3716  */
3717 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
3718                                                 std::vector<int>& elts, std::vector<int>& eltsIndex) const
3719 {
3720   int spaceDim=getSpaceDimension();
3721   int mDim=getMeshDimension();
3722   if(spaceDim==3)
3723     {
3724       if(mDim==3)
3725         {
3726           const double *coords=_coords->getConstPointer();
3727           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3728         }
3729       /*else if(mDim==2)
3730         {
3731           
3732         }*/
3733       else
3734         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
3735     }
3736   else if(spaceDim==2)
3737     {
3738       if(mDim==2)
3739         {
3740           const double *coords=_coords->getConstPointer();
3741           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3742         }
3743       else
3744         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
3745     }
3746   else if(spaceDim==1)
3747     {
3748       if(mDim==1)
3749         {
3750           const double *coords=_coords->getConstPointer();
3751           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
3752         }
3753       else
3754         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
3755     }
3756   else
3757     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
3758 }
3759
3760 /*!
3761  * This method is only available for a mesh with meshDim==2 and spaceDim==2||spaceDim==3.
3762  * This method returns a vector 'cells' where all detected butterfly cells have been added to cells.
3763  * A 2D cell is considered to be butterfly if it exists at least one pair of distinct edges of it that intersect each other
3764  * anywhere excepted their extremities. An INTERP_KERNEL::NORM_NORI3 could \b not be butterfly.
3765  */
3766 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
3767 {
3768   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
3769   if(getMeshDimension()!=2)
3770     throw INTERP_KERNEL::Exception(msg);
3771   int spaceDim=getSpaceDimension();
3772   if(spaceDim!=2 && spaceDim!=3)
3773     throw INTERP_KERNEL::Exception(msg);
3774   const int *conn=_nodal_connec->getConstPointer();
3775   const int *connI=_nodal_connec_index->getConstPointer();
3776   int nbOfCells=getNumberOfCells();
3777   std::vector<double> cell2DinS2;
3778   for(int i=0;i<nbOfCells;i++)
3779     {
3780       int offset=connI[i];
3781       int nbOfNodesForCell=connI[i+1]-offset-1;
3782       if(nbOfNodesForCell<=3)
3783         continue;
3784       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
3785       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
3786       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
3787         cells.push_back(i);
3788       cell2DinS2.clear();
3789     }
3790 }
3791
3792 /*!
3793  * This method is typically requested to unbutterfly 2D linear cells in \b this.
3794  *
3795  * 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.
3796  * 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.
3797  * 
3798  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
3799  * This convex envelop is computed using Jarvis march algorithm.
3800  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
3801  * 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)
3802  * 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.
3803  *
3804  * @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.
3805  */
3806 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D() throw(INTERP_KERNEL::Exception)
3807 {
3808   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
3809     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
3810   checkFullyDefined();
3811   const double *coords=getCoords()->getConstPointer();
3812   int nbOfCells=getNumberOfCells();
3813   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
3814   nodalConnecIndexOut->alloc(nbOfCells+1,1);
3815   std::vector<int> nodalConnecOut;
3816   int *workIndexOut=nodalConnecIndexOut->getPointer();
3817   *workIndexOut=0;
3818   const int *nodalConnecIn=_nodal_connec->getConstPointer();
3819   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
3820   std::set<INTERP_KERNEL::NormalizedCellType> types;
3821   std::vector<int> isChanged;
3822   for(int i=0;i<nbOfCells;i++,workIndexOut++)
3823     {
3824       std::size_t pos=nodalConnecOut.size();
3825       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
3826         isChanged.push_back(i);
3827       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut[pos]);
3828       workIndexOut[1]=(int)nodalConnecOut.size();
3829     }
3830   if(isChanged.empty())
3831     return 0;
3832   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> nodalConnecOut2=DataArrayInt::New();
3833   nodalConnecOut2->alloc((int)nodalConnecOut.size(),1);
3834   std::copy(nodalConnecOut.begin(),nodalConnecOut.end(),nodalConnecOut2->getPointer());
3835   setConnectivity(nodalConnecOut2,nodalConnecIndexOut,false);
3836   _types=types;
3837   DataArrayInt *ret=DataArrayInt::New(); ret->alloc((int)isChanged.size(),1);
3838   std::copy(isChanged.begin(),isChanged.end(),ret->getPointer());
3839   return ret;
3840 }
3841
3842 /*!
3843  * This method is expected to be applied on a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
3844  * This method analyzes only linear extruded 3D cells (NORM_HEXA8,NORM_PENTA6,NORM_HEXGP12...)
3845  * 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).
3846  * Some viewers are very careful of that (SMESH), but ParaVis ignore that.
3847  */
3848 void MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells(std::vector<int>& cells) throw(INTERP_KERNEL::Exception)
3849 {
3850   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
3851   if(getMeshDimension()!=3)
3852     throw INTERP_KERNEL::Exception(msg);
3853   int spaceDim=getSpaceDimension();
3854   if(spaceDim!=3)
3855     throw INTERP_KERNEL::Exception(msg);
3856   //
3857   int nbOfCells=getNumberOfCells();
3858   int *conn=_nodal_connec->getPointer();
3859   const int *connI=_nodal_connec_index->getConstPointer();
3860   const double *coo=getCoords()->getConstPointer();
3861   double vec0[3],vec1[3];
3862   for(int i=0;i<nbOfCells;i++)
3863     {
3864       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
3865       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
3866         {
3867           INTERP_KERNEL::AutoPtr<int> tmp=new int[connI[i+1]-connI[i]-1];
3868           int nbOfNodes=cm.fillSonCellNodalConnectivity(0,conn+connI[i]+1,tmp);
3869           INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(tmp,nbOfNodes,coo,vec0);
3870           const double *pt0=coo+3*conn[connI[i]+1];
3871           const double *pt1=coo+3*conn[connI[i]+nbOfNodes+1];
3872           vec1[0]=pt0[0]-pt1[0]; vec1[1]=pt0[1]-pt1[1]; vec1[2]=pt0[2]-pt1[2];
3873           double dot=vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2];
3874           if(dot<0)
3875             {
3876               cells.push_back(i);
3877               std::copy(conn+connI[i]+1,conn+connI[i+1],(int *)tmp);
3878               for(int j=1;j<nbOfNodes;j++)
3879                 {
3880                   conn[connI[i]+1+j]=tmp[nbOfNodes-j];
3881                   conn[connI[i]+1+j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
3882                 }
3883             }
3884         }
3885     }
3886 }
3887
3888 /*!
3889  * This method is \b NOT const because it can modify 'this'.
3890  * 'this' is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
3891  * @param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
3892  * @param policy specifies the type of extrusion chosen. \b 0 for translation (most simple),
3893  * \b 1 for translation and rotation around point of 'mesh1D'.
3894  * @return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than 'this'.  
3895  */
3896 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
3897 {
3898   checkFullyDefined();
3899   mesh1D->checkFullyDefined();
3900   if(!mesh1D->isContiguous1D())
3901     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
3902   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
3903     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same dimension !");
3904   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3905     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
3906   if(mesh1D->getMeshDimension()!=1)
3907     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
3908   bool isQuad=false;
3909   if(isPresenceOfQuadratic())
3910     {
3911       if(mesh1D->isFullyQuadratic())
3912         isQuad=true;
3913       else
3914         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
3915     }
3916   zipCoords();
3917   int oldNbOfNodes=getNumberOfNodes();
3918   DataArrayDouble *newCoords=0;
3919   switch(policy)
3920     {
3921     case 0:
3922       {
3923         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
3924         break;
3925       }
3926     case 1:
3927       {
3928         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
3929         break;
3930       }
3931     default:
3932       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
3933     }
3934   setCoords(newCoords);
3935   newCoords->decrRef();
3936   MEDCouplingUMesh *ret=buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad);
3937   updateTime();
3938   return ret;
3939 }
3940
3941 /*!
3942  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
3943  * If it is not the case an exception will be thrown.
3944  * This method is non const because the coordinate of 'this' can be appended with some new points issued from
3945  * intersection of plane defined by ('origin','vec').
3946  * This method has one in/out parameter : 'cut3DCurve'.
3947  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
3948  * if cut3DCurve[i]==-2, it means that for cell #i in 'this' nothing has been detected previously.
3949  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
3950  * This method will throw an exception if 'this' contains a non linear segment.
3951  */
3952 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve) throw(INTERP_KERNEL::Exception)
3953 {
3954   checkFullyDefined();
3955   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
3956     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
3957   int ncells=getNumberOfCells();
3958   int nnodes=getNumberOfNodes();
3959   double vec2[3],vec3[3],vec4[3];
3960   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3961   if(normm<1e-6)
3962     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3963   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
3964   const int *conn=_nodal_connec->getConstPointer();
3965   const int *connI=_nodal_connec_index->getConstPointer();
3966   const double *coo=_coords->getConstPointer();
3967   std::vector<double> addCoo;
3968   for(int i=0;i<ncells;i++)
3969     {
3970       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
3971         {
3972           if(cut3DCurve[i]==-2)
3973             {
3974               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
3975               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];
3976               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
3977               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
3978               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
3979                 {
3980                   const double *st2=coo+3*st;
3981                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
3982                   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]));
3983                   if(pos>eps && pos<1-eps)
3984                     {
3985                       int nNode=((int)addCoo.size())/3;
3986                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
3987                       addCoo.insert(addCoo.end(),vec4,vec4+3);
3988                       cut3DCurve[i]=nnodes+nNode;
3989                     }
3990                 }
3991             }
3992         }
3993       else
3994         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
3995     }
3996   if(!addCoo.empty())
3997     {
3998       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
3999       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo2=DataArrayDouble::New();
4000       coo2->alloc(newNbOfNodes,3);
4001       double *tmp=coo2->getPointer();
4002       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4003       std::copy(addCoo.begin(),addCoo.end(),tmp);
4004       DataArrayDouble::SetArrayIn(coo2,_coords);
4005     }
4006 }
4007
4008 /*!
4009  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4010  * @param mesh1D is the input 1D mesh used for translation computation.
4011  * @return newCoords new coords filled by this method. 
4012  */
4013 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4014 {
4015   int oldNbOfNodes=getNumberOfNodes();
4016   int nbOf1DCells=mesh1D->getNumberOfCells();
4017   int spaceDim=getSpaceDimension();
4018   DataArrayDouble *ret=DataArrayDouble::New();
4019   std::vector<bool> isQuads;
4020   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4021   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4022   double *retPtr=ret->getPointer();
4023   const double *coords=getCoords()->getConstPointer();
4024   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4025   std::vector<int> v;
4026   std::vector<double> c;
4027   double vec[3];
4028   v.reserve(3);
4029   c.reserve(6);
4030   for(int i=0;i<nbOf1DCells;i++)
4031     {
4032       v.resize(0);
4033       mesh1D->getNodeIdsOfCell(i,v);
4034       c.resize(0);
4035       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4036       mesh1D->getCoordinatesOfNode(v[0],c);
4037       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4038       for(int j=0;j<oldNbOfNodes;j++)
4039         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4040       if(isQuad)
4041         {
4042           c.resize(0);
4043           mesh1D->getCoordinatesOfNode(v[1],c);
4044           mesh1D->getCoordinatesOfNode(v[0],c);
4045           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4046           for(int j=0;j<oldNbOfNodes;j++)
4047             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4048         }
4049     }
4050   ret->copyStringInfoFrom(*getCoords());
4051   return ret;
4052 }
4053
4054 /*!
4055  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4056  * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4057  * @return newCoords new coords filled by this method. 
4058  */
4059 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4060 {
4061   if(mesh1D->getSpaceDimension()==2)
4062     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4063   if(mesh1D->getSpaceDimension()==3)
4064     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4065   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4066 }
4067
4068 /*!
4069  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4070  * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4071  * @return newCoords new coords filled by this method. 
4072  */
4073 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4074 {
4075   if(isQuad)
4076     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4077   int oldNbOfNodes=getNumberOfNodes();
4078   int nbOf1DCells=mesh1D->getNumberOfCells();
4079   if(nbOf1DCells<2)
4080     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4081   DataArrayDouble *ret=DataArrayDouble::New();
4082   int nbOfLevsInVec=nbOf1DCells+1;
4083   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4084   double *retPtr=ret->getPointer();
4085   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4086   MEDCouplingUMesh *tmp=MEDCouplingUMesh::New();
4087   DataArrayDouble *tmp2=getCoords()->deepCpy();
4088   tmp->setCoords(tmp2);
4089   tmp2->decrRef();
4090   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4091   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4092   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4093   for(int i=1;i<nbOfLevsInVec;i++)
4094     {
4095       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4096       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4097       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4098       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4099       tmp->translate(vec);
4100       double tmp3[2],radius,alpha,alpha0;
4101       const double *p0=i+1<nbOfLevsInVec?begin:third;
4102       const double *p1=i+1<nbOfLevsInVec?end:begin;
4103       const double *p2=i+1<nbOfLevsInVec?third:end;
4104       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4105       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]);
4106       double angle=acos(cosangle/(radius*radius));
4107       tmp->rotate(end,0,angle);
4108       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4109     }
4110   tmp->decrRef();
4111   return ret;
4112 }
4113
4114 /*!
4115  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4116  * @param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4117  * @return newCoords new coords filled by this method. 
4118  */
4119 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const throw(INTERP_KERNEL::Exception)
4120 {
4121   if(isQuad)
4122     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4123   int oldNbOfNodes=getNumberOfNodes();
4124   int nbOf1DCells=mesh1D->getNumberOfCells();
4125   if(nbOf1DCells<2)
4126     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4127   DataArrayDouble *ret=DataArrayDouble::New();
4128   int nbOfLevsInVec=nbOf1DCells+1;
4129   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4130   double *retPtr=ret->getPointer();
4131   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4132   MEDCouplingUMesh *tmp=MEDCouplingUMesh::New();
4133   DataArrayDouble *tmp2=getCoords()->deepCpy();
4134   tmp->setCoords(tmp2);
4135   tmp2->decrRef();
4136   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4137   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4138   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4139   for(int i=1;i<nbOfLevsInVec;i++)
4140     {
4141       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4142       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4143       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4144       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4145       tmp->translate(vec);
4146       double tmp3[2],radius,alpha,alpha0;
4147       const double *p0=i+1<nbOfLevsInVec?begin:third;
4148       const double *p1=i+1<nbOfLevsInVec?end:begin;
4149       const double *p2=i+1<nbOfLevsInVec?third:end;
4150       double vecPlane[3]={
4151         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4152         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4153         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4154       };
4155       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4156       if(norm>1.e-7)
4157         {
4158           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4159           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4160           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4161           double s2=norm2;
4162           double c2=cos(asin(s2));
4163           double m[3][3]={
4164             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4165             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4166             {-vec2[1]*s2, vec2[0]*s2, c2}
4167           };
4168           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]};
4169           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]};
4170           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]};
4171           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4172           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]);
4173           double angle=acos(cosangle/(radius*radius));
4174           tmp->rotate(end,vecPlane,angle);
4175           
4176         }
4177       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4178     }
4179   tmp->decrRef();
4180   return ret;
4181 }
4182
4183 /*!
4184  * This method is private because not easy to use for end user. This method is const contrary to
4185  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4186  * the coords sorted slice by slice.
4187  * @param isQuad specifies presence of quadratic cells.
4188  */
4189 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4190 {
4191   int nbOf1DCells=getNumberOfNodes()/nbOfNodesOf1Lev-1;
4192   int nbOf2DCells=getNumberOfCells();
4193   int nbOf3DCells=nbOf2DCells*nbOf1DCells;
4194   MEDCouplingUMesh *ret=MEDCouplingUMesh::New("Extruded",getMeshDimension()+1);
4195   const int *conn=_nodal_connec->getConstPointer();
4196   const int *connI=_nodal_connec_index->getConstPointer();
4197   DataArrayInt *newConn=DataArrayInt::New();
4198   DataArrayInt *newConnI=DataArrayInt::New();
4199   newConnI->alloc(nbOf3DCells+1,1);
4200   int *newConnIPtr=newConnI->getPointer();
4201   *newConnIPtr++=0;
4202   std::vector<int> newc;
4203   for(int j=0;j<nbOf2DCells;j++)
4204     {
4205       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
4206       *newConnIPtr++=(int)newc.size();
4207     }
4208   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
4209   int *newConnPtr=newConn->getPointer();
4210   int deltaPerLev=isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev;
4211   newConnIPtr=newConnI->getPointer();
4212   for(int iz=0;iz<nbOf1DCells;iz++)
4213     {
4214       if(iz!=0)
4215         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
4216       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
4217         {
4218           int icell=(int)(iter-newc.begin());
4219           if(std::find(newConnIPtr,newConnIPtr+nbOf2DCells,icell)==newConnIPtr+nbOf2DCells)
4220             {
4221               if(*iter!=-1)
4222                 *newConnPtr=(*iter)+iz*deltaPerLev;
4223               else
4224                 *newConnPtr=-1;
4225             }
4226           else
4227             *newConnPtr=(*iter);
4228         }
4229     }
4230   ret->setConnectivity(newConn,newConnI,true);
4231   newConn->decrRef();
4232   newConnI->decrRef();
4233   ret->setCoords(getCoords());
4234   return ret;
4235 }
4236
4237 /*!
4238  * This method returns if 'this' is constituted by only quadratic cells.
4239  */
4240 bool MEDCouplingUMesh::isFullyQuadratic() const
4241 {
4242   checkFullyDefined();
4243   bool ret=true;
4244   int nbOfCells=getNumberOfCells();
4245   for(int i=0;i<nbOfCells && ret;i++)
4246     {
4247       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4248       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4249       ret=cm.isQuadratic();
4250     }
4251   return ret;
4252 }
4253
4254 /*!
4255  * This method returns if there is at least one quadratic cell.
4256  */
4257 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4258 {
4259   checkFullyDefined();
4260   bool ret=false;
4261   int nbOfCells=getNumberOfCells();
4262   for(int i=0;i<nbOfCells && !ret;i++)
4263     {
4264       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4265       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4266       ret=cm.isQuadratic();
4267     }
4268   return ret;
4269 }
4270
4271 /*!
4272  * This method convert quadratic cells to linear cells if any was found.
4273  * If no such cells exists 'this' remains unchanged.
4274  */
4275 void MEDCouplingUMesh::convertQuadraticCellsToLinear() throw(INTERP_KERNEL::Exception)
4276 {
4277   checkFullyDefined();
4278   int nbOfCells=getNumberOfCells();
4279   int delta=0;
4280   for(int i=0;i<nbOfCells;i++)
4281     {
4282       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4283       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4284       if(cm.isQuadratic())
4285         {
4286           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4287           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4288           delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4289         }
4290     }
4291   if(delta==0)
4292     return ;
4293   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4294   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4295   newConn->alloc(getMeshLength()-delta,1);
4296   newConnI->alloc(nbOfCells+1,1);
4297   const int *icptr=_nodal_connec->getConstPointer();
4298   const int *iciptr=_nodal_connec_index->getConstPointer();
4299   int *ocptr=newConn->getPointer();
4300   int *ociptr=newConnI->getPointer();
4301   *ociptr=0;
4302   _types.clear();
4303   for(int i=0;i<nbOfCells;i++,ociptr++)
4304     {
4305       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4306       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4307       if(!cm.isQuadratic())
4308         {
4309           _types.insert(type);
4310           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4311           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4312         }
4313       else
4314         {
4315           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4316           _types.insert(typel);
4317           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4318           int newNbOfNodes=cml.getNumberOfNodes();
4319           *ocptr++=(int)typel;
4320           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4321           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4322         }
4323     }
4324   setConnectivity(newConn,newConnI,false);
4325 }
4326
4327 /*!
4328  * This method tessallates 'this' so that the number of cells remains the same.
4329  * This method works only for meshes with spaceDim equal to 2 and meshDim equal to 2.
4330  * If no cells are quadratic in 'this' (INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ) this method will remain unchanged.
4331  * 
4332  * \b WARNING this method can lead to a uge amount of nodes if eps is very low.
4333  * @param eps specifies the maximal angle (in radian) between 2 subedges of polylinized edge constituting the input polygon.
4334  */
4335 void MEDCouplingUMesh::tessellate2D(double eps) throw(INTERP_KERNEL::Exception)
4336 {
4337   checkFullyDefined();
4338   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
4339     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
4340   double epsa=fabs(eps);
4341   if(epsa<std::numeric_limits<double>::min())
4342     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 !");
4343   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> desc1=DataArrayInt::New();
4344   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> descIndx1=DataArrayInt::New();
4345   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDesc1=DataArrayInt::New();
4346   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revDescIndx1=DataArrayInt::New();
4347   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mDesc=buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
4348   revDesc1=0; revDescIndx1=0;
4349   mDesc->tessellate2DCurve(eps);
4350   subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
4351   setCoords(mDesc->getCoords());
4352 }
4353
4354 /*!
4355  * This method tessallates 'this' so that the number of cells remains the same.
4356  * This method works only for meshes with spaceDim equal to 2 and meshDim equal to 1.
4357  * If no cells are quadratic in 'this' (INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ) this method will remain unchanged.
4358  * 
4359  * \b WARNING this method can lead to a uge amount of nodes if eps is very low.
4360  * @param eps specifies the maximal angle (in radian) between 2 subedges of polylinized edge constituting the input polygon.
4361  */
4362 void MEDCouplingUMesh::tessellate2DCurve(double eps) throw(INTERP_KERNEL::Exception)
4363 {
4364   checkFullyDefined();
4365   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
4366     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurve works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
4367   double epsa=fabs(eps);
4368   if(epsa<std::numeric_limits<double>::min())
4369     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 !");
4370   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
4371   int nbCells=getNumberOfCells();
4372   int nbNodes=getNumberOfNodes();
4373   const int *conn=_nodal_connec->getConstPointer();
4374   const int *connI=_nodal_connec_index->getConstPointer();
4375   const double *coords=_coords->getConstPointer();
4376   std::vector<double> addCoo;
4377   std::vector<int> newConn;
4378   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnI=DataArrayInt::New();
4379   newConnI->alloc(nbCells+1,1);
4380   int *newConnIPtr=newConnI->getPointer();
4381   *newConnIPtr=0;
4382   int tmp1[3];
4383   INTERP_KERNEL::Node *tmp2[3];
4384   std::set<INTERP_KERNEL::NormalizedCellType> types;
4385   for(int i=0;i<nbCells;i++,newConnIPtr++)
4386     {
4387       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4388       if(cm.isQuadratic())
4389         {//assert(connI[i+1]-connI[i]-1==3)
4390           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
4391           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
4392           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
4393           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
4394           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
4395           if(eac)
4396             {
4397               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
4398               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
4399               delete eac;
4400               newConnIPtr[1]=(int)newConn.size();
4401             }
4402           else
4403             {
4404               types.insert(INTERP_KERNEL::NORM_SEG2);
4405               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
4406               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
4407               newConnIPtr[1]=newConnIPtr[0]+3;
4408             }
4409         }
4410       else
4411         {
4412           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4413           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
4414           newConnIPtr[1]=newConnIPtr[0]+3;
4415         }
4416     }
4417   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tasselation : no update needed
4418     return ;
4419   _types=types;
4420   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
4421   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConnArr=DataArrayInt::New();
4422   newConnArr->alloc((int)newConn.size(),1);
4423   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
4424   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
4425   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=DataArrayDouble::New();
4426   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
4427   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
4428   std::copy(addCoo.begin(),addCoo.end(),work);
4429   DataArrayDouble::SetArrayIn(newCoords,_coords);
4430   updateTime();
4431 }
4432
4433 /*!
4434  * This methods modify this by converting each cells into simplex cell, that is too say triangle for meshdim==2 or tetra for meshdim==3.
4435  * This cut into simplex is performed following the parameter 'policy'. This method so typically increases the number of cells of this.
4436  * This method returns new2old array that specifies a each cell of 'this' after the call what was its id it comes.
4437  * 
4438  * The semantic of 'policy' parameter :
4439  * - 1 only QUAD4. For QUAD4 the cut is done along 0-2 diagonal for QUAD4
4440  * - 2 only QUAD4. For QUAD4 the cut is done along 1-3 diagonal for QUAD4
4441  */
4442 DataArrayInt *MEDCouplingUMesh::simplexize(int policy) throw(INTERP_KERNEL::Exception)
4443 {
4444   switch(policy)
4445     {
4446     case 0:
4447       return simplexizePol0();
4448     case 1:
4449       return simplexizePol1();
4450     default:
4451       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexize : unrecognized policy ! Must be 0 or 1 !");
4452     }
4453 }
4454
4455 bool MEDCouplingUMesh::areOnlySimplexCells() const throw(INTERP_KERNEL::Exception)
4456 {
4457   checkFullyDefined();
4458   if(getMeshDimension()<1)
4459     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim >= 1 !");
4460   int nbCells=getNumberOfCells();
4461   const int *conn=_nodal_connec->getConstPointer();
4462   const int *connI=_nodal_connec_index->getConstPointer();
4463   for(int i=0;i<nbCells;i++)
4464     {
4465       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4466       if(!cm.isSimplex())
4467         return false;
4468     }
4469   return true;
4470 }
4471
4472 /*!
4473  * This method implements policy 0 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4474  */
4475 DataArrayInt *MEDCouplingUMesh::simplexizePol0() throw(INTERP_KERNEL::Exception)
4476 {
4477   if(getMeshDimension()!=2)
4478     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
4479   int nbOfCells=getNumberOfCells();
4480   DataArrayInt *ret=DataArrayInt::New();
4481   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
4482   ret->alloc(nbOfCells+nbOfCutCells,1);
4483   if(nbOfCutCells==0)
4484     {
4485       ret->iota(0);
4486       return ret;
4487     }
4488   int *retPt=ret->getPointer();
4489   DataArrayInt *newConn=DataArrayInt::New();
4490   DataArrayInt *newConnI=DataArrayInt::New();
4491   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
4492   newConn->alloc(getMeshLength()+3*nbOfCutCells,1);
4493   int *pt=newConn->getPointer();
4494   int *ptI=newConnI->getPointer();
4495   ptI[0]=0;
4496   const int *oldc=_nodal_connec->getConstPointer();
4497   const int *ci=_nodal_connec_index->getConstPointer();
4498   for(int i=0;i<nbOfCells;i++,ci++)
4499     {
4500       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
4501         {
4502           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
4503                             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
4504           pt=std::copy(tmp,tmp+8,pt);
4505           ptI[1]=ptI[0]+4;
4506           ptI[2]=ptI[0]+8;
4507           *retPt++=i;
4508           *retPt++=i;
4509           ptI+=2;
4510         }
4511       else
4512         {
4513           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4514           ptI[1]=ptI[0]+ci[1]-ci[0];
4515           ptI++;
4516           *retPt++=i;
4517         }
4518     }
4519   _nodal_connec->decrRef();
4520   _nodal_connec=newConn;
4521   _nodal_connec_index->decrRef();
4522   _nodal_connec_index=newConnI;
4523   computeTypes();
4524   updateTime();
4525   return ret;
4526 }
4527
4528 /*!
4529  * This method implements policy 1 of virtual method ParaMEDMEM::MEDCouplingUMesh::simplexize.
4530  */
4531 DataArrayInt *MEDCouplingUMesh::simplexizePol1() throw(INTERP_KERNEL::Exception)
4532 {
4533   if(getMeshDimension()!=2)
4534     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
4535   int nbOfCells=getNumberOfCells();
4536   DataArrayInt *ret=DataArrayInt::New();
4537   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
4538   ret->alloc(nbOfCells+nbOfCutCells,1);
4539   if(nbOfCutCells==0)
4540     {
4541       ret->iota(0);
4542       return ret;
4543     }
4544   int *retPt=ret->getPointer();
4545   DataArrayInt *newConn=DataArrayInt::New();
4546   DataArrayInt *newConnI=DataArrayInt::New();
4547   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
4548   newConn->alloc(getMeshLength()+3*nbOfCutCells,1);
4549   int *pt=newConn->getPointer();
4550   int *ptI=newConnI->getPointer();
4551   ptI[0]=0;
4552   const int *oldc=_nodal_connec->getConstPointer();
4553   const int *ci=_nodal_connec_index->getConstPointer();
4554   for(int i=0;i<nbOfCells;i++,ci++)
4555     {
4556       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
4557         {
4558           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
4559                             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
4560           pt=std::copy(tmp,tmp+8,pt);
4561           ptI[1]=ptI[0]+4;
4562           ptI[2]=ptI[0]+8;
4563           *retPt++=i;
4564           *retPt++=i;
4565           ptI+=2;
4566         }
4567       else
4568         {
4569           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
4570           ptI[1]=ptI[0]+ci[1]-ci[0];
4571           ptI++;
4572           *retPt++=i;
4573         }
4574     }
4575   _nodal_connec->decrRef();
4576   _nodal_connec=newConn;
4577   _nodal_connec_index->decrRef();
4578   _nodal_connec_index=newConnI;
4579   computeTypes();
4580   updateTime();
4581   return ret;
4582 }
4583
4584 /*!
4585  * 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.
4586  * This method completly ignore coordinates.
4587  * @param nodeSubdived is the nodal connectivity of subdivision of edges
4588  * @param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
4589  * @param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
4590  * @param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
4591  */
4592 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex) throw(INTERP_KERNEL::Exception)
4593 {
4594   checkFullyDefined();
4595   if(getMeshDimension()!=2)
4596     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
4597   int nbOfCells=getNumberOfCells();
4598   int *connI=_nodal_connec_index->getPointer();
4599   int newConnLgth=0;
4600   for(int i=0;i<nbOfCells;i++,connI++)
4601     {
4602       int offset=descIndex[i];
4603       int nbOfEdges=descIndex[i+1]-offset;
4604       //
4605       bool ddirect=desc[offset+nbOfEdges-1]>0;
4606       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
4607       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
4608       for(int j=0;j<nbOfEdges;j++)
4609         {
4610           bool direct=desc[offset+j]>0;
4611           int edgeId=std::abs(desc[offset+j])-1;
4612           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
4613             {
4614               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
4615               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
4616               int ref2=direct?id1:id2;
4617               if(ref==ref2)
4618                 {
4619                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
4620                   newConnLgth+=nbOfSubNodes-1;
4621                   ref=direct?id2:id1;
4622                 }
4623               else
4624                 {
4625                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
4626                   throw INTERP_KERNEL::Exception(oss.str().c_str());
4627                 }
4628             }
4629           else
4630             {
4631               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
4632             }
4633         }
4634       newConnLgth++;//+1 is for cell type
4635       connI[1]=newConnLgth;
4636     }
4637   //
4638   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> newConn=DataArrayInt::New();
4639   newConn->alloc(newConnLgth,1);
4640   int *work=newConn->getPointer();
4641   for(int i=0;i<nbOfCells;i++)
4642     {
4643       *work++=INTERP_KERNEL::NORM_POLYGON;
4644       int offset=descIndex[i];
4645       int nbOfEdges=descIndex[i+1]-offset;
4646       for(int j=0;j<nbOfEdges;j++)
4647         {
4648           bool direct=desc[offset+j]>0;
4649           int edgeId=std::abs(desc[offset+j])-1;
4650           if(direct)
4651             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
4652           else
4653             {
4654               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
4655               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
4656               work=std::copy(it,it+nbOfSubNodes-1,work);
4657             }
4658         }
4659     }
4660   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
4661   _types.clear();
4662   if(nbOfCells>0)
4663     _types.insert(INTERP_KERNEL::NORM_POLYGON);
4664 }
4665
4666 /*!
4667  * This method converts all degenerated cells to simpler cells. For example a NORM_QUAD4 cell consituted from 2 same node id in its
4668  * nodal connectivity will be transform to a NORM_TRI3 cell.
4669  * This method works \b only \b on \b linear cells.
4670  * This method works on nodes ids, that is to say a call to ParaMEDMEM::MEDCouplingUMesh::mergeNodes
4671  * method could be usefull before calling this method in case of presence of several pair of nodes located on same position.
4672  * This method throws an exception if 'this' is not fully defined (connectivity).
4673  * 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.
4674  */
4675 void MEDCouplingUMesh::convertDegeneratedCells() throw(INTERP_KERNEL::Exception)
4676 {
4677   checkFullyDefined();
4678   if(getMeshDimension()<=1)
4679     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4680   int nbOfCells=getNumberOfCells();
4681   if(nbOfCells<1)
4682     return ;
4683   int initMeshLgth=getMeshLength();
4684   int *conn=_nodal_connec->getPointer();
4685   int *index=_nodal_connec_index->getPointer();
4686   int posOfCurCell=0;
4687   int newPos=0;
4688   int lgthOfCurCell;
4689   for(int i=0;i<nbOfCells;i++)
4690     {
4691       lgthOfCurCell=index[i+1]-posOfCurCell;
4692       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4693       int newLgth;
4694       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4695                                                                                                      conn+newPos+1,newLgth);
4696       conn[newPos]=newType;
4697       newPos+=newLgth+1;
4698       posOfCurCell=index[i+1];
4699       index[i+1]=newPos;
4700     }
4701   if(newPos!=initMeshLgth)
4702     _nodal_connec->reAlloc(newPos);
4703   computeTypes();
4704 }
4705
4706 /*!
4707  * This method checks that all or only polygons (depending 'polyOnly' parameter) 2D cells are correctly oriented relative to 'vec' vector.
4708  * The 'vec' vector has to have a non nul norm.
4709  * If not 'cells' parameter will be appended with cellIds of incorrect cells.
4710  * @throw when 'this' is not a mesh with meshdim==2 and spacedim==3
4711  */
4712 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const throw(INTERP_KERNEL::Exception)
4713 {
4714   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4715     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4716   int nbOfCells=getNumberOfCells();
4717   const int *conn=_nodal_connec->getConstPointer();
4718   const int *connI=_nodal_connec_index->getConstPointer();
4719   const double *coordsPtr=_coords->getConstPointer();
4720   for(int i=0;i<nbOfCells;i++)
4721     {
4722       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4723       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4724         {
4725           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4726           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4727             cells.push_back(i);
4728         }
4729     }
4730 }
4731
4732 /*!
4733  * This method orient correctly (if needed) all or only polygons (depending 'polyOnly' parameter)  2D cells are correctly oriented relative to 'vec' vector.
4734  * The 'vec' vector has to have a non nul norm.
4735  * @throw when 'this' is not a mesh with meshdim==2 and spacedim==3
4736  */
4737 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly) throw(INTERP_KERNEL::Exception)
4738 {
4739   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4740     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4741   int nbOfCells=getNumberOfCells();
4742   int *conn=_nodal_connec->getPointer();
4743   const int *connI=_nodal_connec_index->getConstPointer();
4744   const double *coordsPtr=_coords->getConstPointer();
4745   bool isModified=false;
4746   for(int i=0;i<nbOfCells;i++)
4747     {
4748       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4749       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4750         {
4751           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4752           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4753             {
4754               isModified=true;
4755               std::vector<int> tmp(connI[i+1]-connI[i]-2);
4756               std::copy(conn+connI[i]+2,conn+connI[i+1],tmp.rbegin());
4757               std::copy(tmp.begin(),tmp.end(),conn+connI[i]+2);
4758             }
4759         }
4760     }
4761   if(isModified)
4762     _nodal_connec->declareAsNew();
4763   updateTime();
4764 }
4765
4766 /*!
4767  * This method checks that all polyhedrons cells have correctly oriented faces.
4768  * If not, 'cells' parameter will be appended with cellIds of incorrect cells.
4769  * @throw when 'this' is not a mesh with meshdim==3 and spacedim==3
4770  */
4771 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const throw(INTERP_KERNEL::Exception)
4772 {
4773   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4774     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4775   int nbOfCells=getNumberOfCells();
4776   const int *conn=_nodal_connec->getConstPointer();
4777   const int *connI=_nodal_connec_index->getConstPointer();
4778   const double *coordsPtr=_coords->getConstPointer();
4779   for(int i=0;i<nbOfCells;i++)
4780     {
4781       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4782       if(type==INTERP_KERNEL::NORM_POLYHED)
4783         {
4784           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4785             cells.push_back(i);
4786         }
4787     }
4788 }
4789
4790 /*!
4791  * This method tries to orient correctly polhedrons cells.
4792  * @throw when 'this' is not a mesh with meshdim==3 and spacedim==3. An exception is also thrown when the attempt of reparation fails.
4793  */
4794 void MEDCouplingUMesh::orientCorrectlyPolyhedrons() throw(INTERP_KERNEL::Exception)
4795 {
4796   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4797     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4798   int nbOfCells=getNumberOfCells();
4799   int *conn=_nodal_connec->getPointer();
4800   const int *connI=_nodal_connec_index->getConstPointer();
4801   const double *coordsPtr=_coords->getConstPointer();
4802   bool isModified=false;
4803   for(int i=0;i<nbOfCells;i++)
4804     {
4805       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4806       if(type==INTERP_KERNEL::NORM_POLYHED)
4807         if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4808           {
4809             TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4810             isModified=true;
4811           }
4812     }
4813   if(isModified)
4814     _nodal_connec->declareAsNew();
4815   updateTime();
4816 }
4817
4818 /*!
4819  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
4820  * If it is not the case an exception will be thrown.
4821  * This method is fast because the first cell of 'this' is used to compute the plane.
4822  * @param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
4823  * @param pos output of size at least 3 used to store a point owned of searched plane.
4824  */
4825 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const throw(INTERP_KERNEL::Exception)
4826 {
4827   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4828     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
4829   const int *conn=_nodal_connec->getConstPointer();
4830   const int *connI=_nodal_connec_index->getConstPointer();
4831   const double *coordsPtr=_coords->getConstPointer();
4832   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
4833   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
4834 }
4835
4836 /*!
4837  * The returned newly created field has to be managed by the caller.
4838  * 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.
4839  * This method for the moment only deals with NORM_TRI3, NORM_QUAD4 and NORM_TETRA4 geometric types.
4840  * If a cell has an another type an exception will be thrown.
4841  */
4842 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const throw(INTERP_KERNEL::Exception)
4843 {
4844   checkCoherency();
4845   int spaceDim=getSpaceDimension();
4846   int meshDim=getMeshDimension();
4847   if(spaceDim!=2 && spaceDim!=3)
4848     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
4849   if(meshDim!=2 && meshDim!=3)
4850     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
4851   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
4852   ret->setMesh(this);
4853   int nbOfCells=getNumberOfCells();
4854   DataArrayDouble *arr=DataArrayDouble::New();
4855   arr->alloc(nbOfCells,1);
4856   double *pt=arr->getPointer();
4857   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
4858   arr->decrRef();
4859   const int *conn=_nodal_connec->getConstPointer();
4860   const int *connI=_nodal_connec_index->getConstPointer();
4861   const double *coo=_coords->getConstPointer();
4862   double tmp[12];
4863   for(int i=0;i<nbOfCells;i++,pt++)
4864     {
4865       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
4866       switch(t)
4867         {
4868           case INTERP_KERNEL::NORM_TRI3:
4869             {
4870               FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
4871               *pt=INTERP_KERNEL::triEdgeRatio(tmp);
4872               break;
4873             }
4874           case INTERP_KERNEL::NORM_QUAD4:
4875             {
4876               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4877               *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
4878               break;
4879             }
4880           case INTERP_KERNEL::NORM_TETRA4:
4881             {
4882               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4883               *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
4884               break;
4885             }
4886         default:
4887           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
4888         }
4889       conn+=connI[i+1]-connI[i];
4890     }
4891   ret->setName("EdgeRatio");
4892   ret->incrRef();
4893   return ret;
4894 }
4895
4896 /*!
4897  * The returned newly created field has to be managed by the caller.
4898  * 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.
4899  * This method for the moment only deals with NORM_TRI3, NORM_QUAD4 and NORM_TETRA4 geometric types.
4900  * If a cell has an another type an exception will be thrown.
4901  */
4902 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const throw(INTERP_KERNEL::Exception)
4903 {
4904   checkCoherency();
4905   int spaceDim=getSpaceDimension();
4906   int meshDim=getMeshDimension();
4907   if(spaceDim!=2 && spaceDim!=3)
4908     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
4909   if(meshDim!=2 && meshDim!=3)
4910     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
4911   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
4912   ret->setMesh(this);
4913   int nbOfCells=getNumberOfCells();
4914   DataArrayDouble *arr=DataArrayDouble::New();
4915   arr->alloc(nbOfCells,1);
4916   double *pt=arr->getPointer();
4917   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
4918   arr->decrRef();
4919   const int *conn=_nodal_connec->getConstPointer();
4920   const int *connI=_nodal_connec_index->getConstPointer();
4921   const double *coo=_coords->getConstPointer();
4922   double tmp[12];
4923   for(int i=0;i<nbOfCells;i++,pt++)
4924     {
4925       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
4926       switch(t)
4927         {
4928           case INTERP_KERNEL::NORM_TRI3:
4929             {
4930               FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
4931               *pt=INTERP_KERNEL::triAspectRatio(tmp);
4932               break;
4933             }
4934           case INTERP_KERNEL::NORM_QUAD4:
4935             {
4936               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4937               *pt=INTERP_KERNEL::quadAspectRatio(tmp);
4938               break;
4939             }
4940           case INTERP_KERNEL::NORM_TETRA4:
4941             {
4942               FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
4943               *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
4944               break;
4945             }
4946         default:
4947           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
4948         }
4949       conn+=connI[i+1]-connI[i];
4950     }
4951   ret->setName("AspectRatio");
4952   ret->incrRef();
4953   return ret;
4954 }
4955
4956 /*!
4957  * The returned newly created field has to be managed by the caller.
4958  * 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.
4959  * This method for the moment only deals with NORM_QUAD4 geometric type.
4960  * If a cell has an another type an exception will be thrown.
4961  */
4962 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const throw(INTERP_KERNEL::Exception)
4963 {
4964   checkCoherency();
4965   int spaceDim=getSpaceDimension();
4966   int meshDim=getMeshDimension();
4967   if(spaceDim!=3)
4968     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
4969   if(meshDim!=2)
4970     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
4971   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
4972   ret->setMesh(this);
4973   int nbOfCells=getNumberOfCells();
4974   DataArrayDouble *arr=DataArrayDouble::New();
4975   arr->alloc(nbOfCells,1);
4976   double *pt=arr->getPointer();
4977   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
4978   arr->decrRef();
4979   const int *conn=_nodal_connec->getConstPointer();
4980   const int *connI=_nodal_connec_index->getConstPointer();
4981   const double *coo=_coords->getConstPointer();
4982   double tmp[12];
4983   for(int i=0;i<nbOfCells;i++,pt++)
4984     {
4985       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
4986       switch(t)
4987         {
4988           case INTERP_KERNEL::NORM_QUAD4:
4989             {
4990               FillInCompact3DMode(3,4,conn+1,coo,tmp);
4991               *pt=INTERP_KERNEL::quadWarp(tmp);
4992               break;
4993             }
4994         default:
4995           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
4996         }
4997       conn+=connI[i+1]-connI[i];
4998     }
4999   ret->setName("Warp");
5000   ret->incrRef();
5001   return ret;
5002 }
5003
5004 /*!
5005  * The returned newly created field has to be managed by the caller.
5006  * 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.
5007  * This method for the moment only deals with NORM_QUAD4 geometric type.
5008  * If a cell has an another type an exception will be thrown.
5009  */
5010 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const throw(INTERP_KERNEL::Exception)
5011 {
5012   checkCoherency();
5013   int spaceDim=getSpaceDimension();
5014   int meshDim=getMeshDimension();
5015   if(spaceDim!=3)
5016     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5017   if(meshDim!=2)
5018     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5019   MEDCouplingAutoRefCountObjectPtr<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,NO_TIME);
5020   ret->setMesh(this);
5021   int nbOfCells=getNumberOfCells();
5022   DataArrayDouble *arr=DataArrayDouble::New();
5023   arr->alloc(nbOfCells,1);
5024   double *pt=arr->getPointer();
5025   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5026   arr->decrRef();
5027   const int *conn=_nodal_connec->getConstPointer();
5028   const int *connI=_nodal_connec_index->getConstPointer();
5029   const double *coo=_coords->getConstPointer();
5030   double tmp[12];
5031   for(int i=0;i<nbOfCells;i++,pt++)
5032     {
5033       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5034       switch(t)
5035         {
5036           case INTERP_KERNEL::NORM_QUAD4:
5037             {
5038               FillInCompact3DMode(3,4,conn+1,coo,tmp);
5039               *pt=INTERP_KERNEL::quadSkew(tmp);
5040               break;
5041             }
5042         default:
5043           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5044         }
5045       conn+=connI[i+1]-connI[i];
5046     }
5047   ret->setName("Skew");
5048   ret->incrRef();
5049   return ret;
5050 }
5051
5052 /*!
5053  * This method aggregate the bbox of each cell and put it into bbox parameter.
5054  * @param bbox out parameter of size 2*spacedim*nbOfcells.
5055  */
5056 void MEDCouplingUMesh::getBoundingBoxForBBTree(std::vector<double>& bbox) const
5057 {
5058   int spaceDim=getSpaceDimension();
5059   int nbOfCells=getNumberOfCells();
5060   bbox.resize(2*nbOfCells*spaceDim);
5061   for(int i=0;i<nbOfCells*spaceDim;i++)
5062     {
5063       bbox[2*i]=std::numeric_limits<double>::max();
5064       bbox[2*i+1]=-std::numeric_limits<double>::max();
5065     }
5066   const double *coordsPtr=_coords->getConstPointer();
5067   const int *conn=_nodal_connec->getConstPointer();
5068   const int *connI=_nodal_connec_index->getConstPointer();
5069   for(int i=0;i<nbOfCells;i++)
5070     {
5071       int offset=connI[i]+1;
5072       int nbOfNodesForCell=connI[i+1]-offset;
5073       for(int j=0;j<nbOfNodesForCell;j++)
5074         {
5075           int nodeId=conn[offset+j];
5076           if(nodeId>=0)
5077             for(int k=0;k<spaceDim;k++)
5078               {
5079                 bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5080                 bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5081               }
5082         }
5083     }
5084 }
5085
5086 /// @cond INTERNAL
5087
5088 namespace ParaMEDMEMImpl
5089 {
5090   class ConnReader
5091   {
5092   public:
5093     ConnReader(const int *c, int val):_conn(c),_val(val) { }
5094     bool operator() (const int& pos) { return _conn[pos]!=_val; }
5095   private:
5096     const int *_conn;
5097     int _val;
5098   };
5099
5100   class ConnReader2
5101   {
5102   public:
5103     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
5104     bool operator() (const int& pos) { return _conn[pos]==_val; }
5105   private:
5106     const int *_conn;
5107     int _val;
5108   };
5109 }
5110
5111 /// @endcond
5112
5113 /*!
5114  * This method expects that 'this' is sorted by types. If not an exception will be thrown.
5115  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5116  * 'this' is composed in cell types.
5117  * The returned array is of size 3*n where n is the number of different types present in 'this'. 
5118  * For every k in [0,n] ret[3*k+2]==0 because it has no sense here. 
5119  * This parameter is kept only for compatibility with other methode listed above.
5120  */
5121 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const throw(INTERP_KERNEL::Exception)
5122 {
5123   checkConnectivityFullyDefined();
5124   const int *conn=_nodal_connec->getConstPointer();
5125   const int *connI=_nodal_connec_index->getConstPointer();
5126   const int *work=connI;
5127   int nbOfCells=getNumberOfCells();
5128   std::size_t n=getAllTypes().size();
5129   std::vector<int> ret(3*n,0); //ret[3*k+2]==0 because it has no sense here
5130   std::set<INTERP_KERNEL::NormalizedCellType> types;
5131   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5132     {
5133       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5134       if(types.find(typ)!=types.end())
5135         {
5136           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5137           oss << " is not contiguous !";
5138           throw INTERP_KERNEL::Exception(oss.str().c_str());
5139         }
5140       types.insert(typ);
5141       ret[3*i]=typ;
5142       const int *work2=std::find_if(work+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,typ));
5143       ret[3*i+1]=(int)std::distance(work,work2);
5144       work=work2;
5145     }
5146   return ret;
5147 }
5148
5149 /*!
5150  * This method is used to check that this has contiguous cell type in same order than described in 'code'.
5151  * only for types cell, type node is not managed.
5152  * Format of 'code' is the following. 'code' should be of size 3*n and non empty. If not an exception is thrown.
5153  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5154  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5155  * If 2 or more same geometric type is in 'code' and exception is thrown too.
5156  *
5157  * This method firstly checks
5158  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5159  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5160  * an exception is thrown too.
5161  * 
5162  * If all geometric types in 'code' are exactly those in 'this' null pointer is returned.
5163  * If it exists a geometric type in 'this' \b not in 'code' \b no exception is thrown 
5164  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
5165  */
5166 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const throw(INTERP_KERNEL::Exception)
5167 {
5168   if(code.empty())
5169     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5170   std::size_t sz=code.size();
5171   std::size_t n=sz/3;
5172   if(sz%3!=0)
5173     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5174   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5175   int nb=0;
5176   for(std::size_t i=0;i<n;i++)
5177     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5178       {
5179         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5180         nb+=code[3*i+1];
5181         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5182           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5183       }
5184   if(types.size()!=n)
5185     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5186   if(idsPerType.empty())
5187     {
5188       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5189         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5190       if(types.size()==_types.size())
5191         return 0;
5192     }
5193   DataArrayInt *ret=DataArrayInt::New();
5194   ret->alloc(nb,1);
5195   int *retPtr=ret->getPointer();
5196   const int *connI=_nodal_connec_index->getConstPointer();
5197   const int *conn=_nodal_connec->getConstPointer();
5198   int nbOfCells=getNumberOfCells();
5199   const int *i=connI;
5200   int kk=0;
5201   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5202     {
5203       i=std::find_if(i,connI+nbOfCells,ParaMEDMEMImpl::ConnReader2(conn,(int)(*it)));
5204       int offset=(int)std::distance(connI,i);
5205       if(code[3*kk+2]==-1)
5206         {
5207           const int *j=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)(*it)));
5208           std::size_t pos2=std::distance(i,j);
5209           for(std::size_t k=0;k<pos2;k++)
5210             *retPtr++=(int)k+offset;
5211           i=j;
5212         }
5213       else
5214         {
5215           retPtr=std::transform(idsPerType[code[3*kk+2]]->getConstPointer(),idsPerType[code[3*kk+2]]->getConstPointer()+idsPerType[code[3*kk+2]]->getNbOfElems(),
5216                                 retPtr,std::bind2nd(std::plus<int>(),offset));
5217         }
5218     }
5219   return ret;
5220 }
5221
5222 /*!
5223  * This method makes the hypothesis that 'this' is sorted by type. If not an exception will be thrown.
5224  * This method is the opposite of MEDCouplingUMesh::checkTypeConsistencyAndContig method. Given a list of cells in 'profile' it returns a list of profiles sorted by geo type.
5225  * This method has 1 input 'profile' and 2 outputs 'code' and 'idsPerType'.
5226  * @throw if 'profile' has not exactly one component. It throws too, if 'profile' contains some values not in [0,getNumberOfCells()) or if 'this' is not fully defined
5227  */
5228 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const throw(INTERP_KERNEL::Exception)
5229 {
5230   if(profile->getNumberOfComponents()!=1)
5231     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5232   checkConnectivityFullyDefined();
5233   const int *conn=_nodal_connec->getConstPointer();
5234   const int *connI=_nodal_connec_index->getConstPointer();
5235   int nbOfCells=getNumberOfCells();
5236   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5237   std::vector<int> typeRangeVals(1);
5238   for(const int *i=connI;i!=connI+nbOfCells;)
5239     {
5240       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5241       if(std::find(types.begin(),types.end(),curType)!=types.end())
5242         {
5243           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5244         }
5245       types.push_back(curType);
5246       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5247       typeRangeVals.push_back((int)std::distance(connI,i));
5248     }
5249   //
5250   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
5251   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5252   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp0=castArr;
5253   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1=rankInsideCast;
5254   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp2=castsPresent;
5255   //
5256   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
5257   code.resize(3*nbOfCastsFinal);
5258   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsInPflPerType2;
5259   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > idsPerType2;
5260   for(int i=0;i<nbOfCastsFinal;i++)
5261     {
5262       int castId=castsPresent->getIJ(i,0);
5263       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp3=castArr->getIdsEqual(castId);
5264       idsInPflPerType2.push_back(tmp3);
5265       code[3*i]=(int)types[castId];
5266       code[3*i+1]=tmp3->getNumberOfTuples();
5267       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
5268       if(tmp4->getNumberOfTuples()!=typeRangeVals[castId+1]-typeRangeVals[castId] || !tmp4->isIdentity())
5269         {
5270           tmp4->copyStringInfoFrom(*profile);
5271           idsPerType2.push_back(tmp4);
5272           code[3*i+2]=(int)idsPerType2.size()-1;
5273         }
5274       else
5275         {
5276           code[3*i+2]=-1;
5277         }
5278     }
5279   std::size_t sz2=idsInPflPerType2.size();
5280   idsInPflPerType.resize(sz2);
5281   for(std::size_t i=0;i<sz2;i++)
5282     {
5283       DataArrayInt *locDa=idsInPflPerType2[i];
5284       locDa->incrRef();
5285       idsInPflPerType[i]=locDa;
5286     }
5287   std::size_t sz=idsPerType2.size();
5288   idsPerType.resize(sz);
5289   for(std::size_t i=0;i<sz;i++)
5290     {
5291       DataArrayInt *locDa=idsPerType2[i];
5292       locDa->incrRef();
5293       idsPerType[i]=locDa;
5294     }
5295 }
5296
5297 /*!
5298  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5299  * This method make the assumption that 'this' and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5300  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5301  * 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.
5302  */
5303 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const throw(INTERP_KERNEL::Exception)
5304 {
5305   checkFullyDefined();
5306   nM1LevMesh->checkFullyDefined();
5307   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5308     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5309   if(_coords!=nM1LevMesh->getCoords())
5310     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5311   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp0=DataArrayInt::New();
5312   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1=DataArrayInt::New();
5313   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5314   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
5315   desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
5316   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5317   tmp->setConnectivity(tmp0,tmp1);
5318   tmp->renumberCells(ret0->getConstPointer(),false);
5319   revDesc=tmp->getNodalConnectivity();
5320   revDescIndx=tmp->getNodalConnectivityIndex();
5321   DataArrayInt *ret=0;
5322   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5323     {
5324       int tmp2;
5325       ret->getMaxValue(tmp2);
5326       ret->decrRef();
5327       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5328       throw INTERP_KERNEL::Exception(oss.str().c_str());
5329     }
5330   nM1LevMeshIds=ret;
5331   //
5332   revDesc->incrRef();
5333   revDescIndx->incrRef();
5334   ret1->incrRef();
5335   ret0->incrRef();
5336   meshnM1Old2New=ret0;
5337   return ret1;
5338 }
5339
5340 /*!
5341  * This method sorts cell in this so that cells are sorted by cell type specified by MEDMEM and so for MED file.
5342  * It avoids to deal with renum in MEDLoader so it is usefull for MED file R/W with multi types.
5343  * This method returns a newly allocated array old2New.
5344  * This method expects that connectivity of this is set. If not an exception will be thrown. Coordinates are not taken into account.
5345  */
5346 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt() throw(INTERP_KERNEL::Exception)
5347 {
5348   checkConnectivityFullyDefined();
5349   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5350   renumberCells(ret->getConstPointer(),false);
5351   ret->incrRef();
5352   return ret;
5353 }
5354
5355 /*!
5356  * This methods checks that cells are sorted by their types.
5357  * This method makes asumption (no check) that connectivity is correctly set before calling.
5358  */
5359 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5360 {
5361   checkFullyDefined();
5362   const int *conn=_nodal_connec->getConstPointer();
5363   const int *connI=_nodal_connec_index->getConstPointer();
5364   int nbOfCells=getNumberOfCells();
5365   std::set<INTERP_KERNEL::NormalizedCellType> types;
5366   for(const int *i=connI;i!=connI+nbOfCells;)
5367     {
5368       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5369       if(types.find(curType)!=types.end())
5370         return false;
5371       types.insert(curType);
5372       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5373     }
5374   return true;
5375 }
5376
5377 /*!
5378  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5379  * that the order is specified in array defined by [orderBg,orderEnd). 
5380  */
5381 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5382 {
5383   checkFullyDefined();
5384   const int *conn=_nodal_connec->getConstPointer();
5385   const int *connI=_nodal_connec_index->getConstPointer();
5386   int nbOfCells=getNumberOfCells();
5387   int lastPos=-1;
5388   for(const int *i=connI;i!=connI+nbOfCells;)
5389     {
5390       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5391       int pos=(int)std::distance(orderBg,std::find(orderBg,orderEnd,curType));
5392       if(pos<=lastPos)
5393         return false;
5394       lastPos=pos;
5395       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5396     }
5397   return true;
5398 }
5399
5400 /*!
5401  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
5402  * 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
5403  * 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'.
5404  */
5405 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const throw(INTERP_KERNEL::Exception)
5406 {
5407   checkConnectivityFullyDefined();
5408   int nbOfCells=getNumberOfCells();
5409   const int *conn=_nodal_connec->getConstPointer();
5410   const int *connI=_nodal_connec_index->getConstPointer();
5411   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpa=DataArrayInt::New();
5412   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpb=DataArrayInt::New();
5413   tmpa->alloc(nbOfCells,1);
5414   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
5415   tmpb->fillWithZero();
5416   int *tmp=tmpa->getPointer();
5417   int *tmp2=tmpb->getPointer();
5418   for(const int *i=connI;i!=connI+nbOfCells;i++)
5419     {
5420       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
5421       if(where!=orderEnd)
5422         {
5423           int pos=(int)std::distance(orderBg,where);
5424           tmp2[pos]++;
5425           tmp[std::distance(connI,i)]=pos;
5426         }
5427       else
5428         {
5429           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
5430           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
5431           oss << " has a type " << cm.getRepr() << " not in input array of type !";
5432           throw INTERP_KERNEL::Exception(oss.str().c_str());
5433         }
5434     }
5435   nbPerType=tmpb;
5436   tmpa->incrRef();
5437   tmpb->incrRef();
5438   return tmpa;
5439 }
5440
5441 /*!
5442  * 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'.
5443  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
5444  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
5445  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
5446  */
5447 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const throw(INTERP_KERNEL::Exception)
5448 {
5449   DataArrayInt *nbPerType=0;
5450   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
5451   nbPerType->decrRef();
5452   return tmpa->buildPermArrPerLevel();
5453 }
5454
5455 /*!
5456  * This method reorganize the cells of 'this' so that the cells with same geometric types are put together.
5457  * The number of cells remains unchanged after the call of this method.
5458  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
5459  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
5460  *
5461  * @return the array giving the correspondance old to new.
5462  */
5463 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
5464 {
5465   checkFullyDefined();
5466   computeTypes();
5467   const int *conn=_nodal_connec->getConstPointer();
5468   const int *connI=_nodal_connec_index->getConstPointer();
5469   int nbOfCells=getNumberOfCells();
5470   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5471   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
5472     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
5473       {
5474         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5475         types.push_back(curType);
5476         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
5477       }
5478   DataArrayInt *ret=DataArrayInt::New();
5479   ret->alloc(nbOfCells,1);
5480   int *retPtr=ret->getPointer();
5481   std::fill(retPtr,retPtr+nbOfCells,-1);
5482   int newCellId=0;
5483   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5484     {
5485       for(const int *i=connI;i!=connI+nbOfCells;i++)
5486         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5487           retPtr[std::distance(connI,i)]=newCellId++;
5488     }
5489   renumberCells(retPtr,false);
5490   return ret;
5491 }
5492
5493 /*!
5494  * This method splits 'this' into as mush as untructured meshes that consecutive set of same type cells.
5495  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
5496  * This method makes asumption that connectivity is correctly set before calling.
5497  */
5498 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
5499 {
5500   checkFullyDefined();
5501   const int *conn=_nodal_connec->getConstPointer();
5502   const int *connI=_nodal_connec_index->getConstPointer();
5503   int nbOfCells=getNumberOfCells();
5504   std::vector<MEDCouplingUMesh *> ret;
5505   for(const int *i=connI;i!=connI+nbOfCells;)
5506     {
5507       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5508       int beginCellId=(int)std::distance(connI,i);
5509       i=std::find_if(i+1,connI+nbOfCells,ParaMEDMEMImpl::ConnReader(conn,(int)curType));
5510       int endCellId=(int)std::distance(connI,i);
5511       int sz=endCellId-beginCellId;
5512       int *cells=new int[sz];
5513       for(int j=0;j<sz;j++)
5514         cells[j]=beginCellId+j;
5515       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
5516       delete [] cells;
5517       ret.push_back(m);
5518     }
5519   return ret;
5520 }
5521
5522 /*!
5523  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
5524  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
5525  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
5526  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
5527  * are not used here to avoid the build of big permutation array.
5528  *
5529  * \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
5530  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
5531  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
5532  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
5533  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
5534  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
5535  * \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
5536  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
5537  */
5538 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
5539                                                                             DataArrayInt *&szOfCellGrpOfSameType,
5540                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType) throw(INTERP_KERNEL::Exception)
5541 {
5542   std::vector<const MEDCouplingUMesh *> ms2;
5543   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
5544     if(*it)
5545       {
5546         (*it)->checkConnectivityFullyDefined();
5547         ms2.push_back(*it);
5548       }
5549   if(ms2.empty())
5550     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
5551   const DataArrayDouble *refCoo=ms2[0]->getCoords();
5552   int meshDim=ms2[0]->getMeshDimension();
5553   std::vector<const MEDCouplingUMesh *> m1ssm;
5554   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > m1ssmAuto;
5555   //
5556   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
5557   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > m1ssmSingleAuto;
5558   int fake=0,rk=0;
5559   std::vector<int> ret1Data;
5560   std::vector<int> ret2Data;
5561   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
5562     {
5563       if(meshDim!=(*it)->getMeshDimension())
5564         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
5565       if(refCoo!=(*it)->getCoords())
5566         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
5567       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
5568       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
5569       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > >(m1ssmAuto));
5570       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
5571         {
5572           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
5573           m1ssmSingleAuto.push_back(singleCell);
5574           m1ssmSingle.push_back(singleCell);
5575           ret1Data.push_back((*it2)->getNumberOfCells()); ret2Data.push_back(rk);
5576         }
5577     }
5578   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc((int)m1ssmSingle.size(),1); std::copy(ret1Data.begin(),ret1Data.end(),ret1->getPointer());
5579   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret2=DataArrayInt::New(); ret2->alloc((int)m1ssmSingle.size(),1); std::copy(ret2Data.begin(),ret2Data.end(),ret2->getPointer());
5580   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
5581   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
5582   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
5583   for(std::size_t i=0;i<m1ssm.size();i++)
5584     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
5585   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
5586   szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
5587   idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
5588   ret0->incrRef();
5589   return ret0;
5590 }
5591
5592 /*!
5593  * This method returns a newly created DataArrayInt instance.
5594  * This method retrieves cell ids in [begin,end) that have the type 'type'.
5595  */
5596 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const throw(INTERP_KERNEL::Exception)
5597 {
5598   checkFullyDefined();
5599   std::vector<int> r;
5600   const int *conn=_nodal_connec->getConstPointer();
5601   const int *connIndex=_nodal_connec_index->getConstPointer();
5602   for(const int *w=begin;w!=end;w++)
5603     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
5604       r.push_back(*w);
5605   DataArrayInt *ret=DataArrayInt::New();
5606   ret->alloc((int)r.size(),1);
5607   std::copy(r.begin(),r.end(),ret->getPointer());
5608   return ret;
5609 }
5610
5611 /*!
5612  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
5613  * are in [0:getNumberOfCells())
5614  */
5615 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const throw(INTERP_KERNEL::Exception)
5616 {
5617   checkFullyDefined();
5618   const int *conn=_nodal_connec->getConstPointer();
5619   const int *connI=_nodal_connec_index->getConstPointer();
5620   int nbOfCells=getNumberOfCells();
5621   std::set<INTERP_KERNEL::NormalizedCellType> types=getAllTypes();
5622   int *tmp=new int[nbOfCells];
5623   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
5624     {
5625       int j=0;
5626       for(const int *i=connI;i!=connI+nbOfCells;i++)
5627         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
5628           tmp[std::distance(connI,i)]=j++;
5629     }
5630   DataArrayInt *ret=DataArrayInt::New();
5631   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
5632   ret->copyStringInfoFrom(*da);
5633   int *retPtr=ret->getPointer();
5634   const int *daPtr=da->getConstPointer();
5635   int nbOfElems=da->getNbOfElems();
5636   for(int k=0;k<nbOfElems;k++)
5637     retPtr[k]=tmp[daPtr[k]];
5638   delete [] tmp;
5639   return ret;
5640 }
5641
5642 /*!
5643  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
5644  * cells whose ids is in 'idsPerGeoType' array.
5645  * This method conserves coords and name of mesh.
5646  */
5647 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
5648 {
5649   std::vector<int> idsTokeep;
5650   int nbOfCells=getNumberOfCells();
5651   int j=0;
5652   for(int i=0;i<nbOfCells;i++)
5653     if(getTypeOfCell(i)!=type)
5654       idsTokeep.push_back(i);
5655     else
5656       {
5657         if(std::find(idsPerGeoTypeBg,idsPerGeoTypeEnd,j)!=idsPerGeoTypeEnd)
5658           idsTokeep.push_back(i);
5659         j++;
5660       }
5661   MEDCouplingPointSet *ret=buildPartOfMySelf(&idsTokeep[0],&idsTokeep[0]+idsTokeep.size(),true);
5662   MEDCouplingUMesh *ret2=dynamic_cast<MEDCouplingUMesh *>(ret);
5663   if(!ret2)
5664     {
5665       ret->decrRef();
5666       return 0;
5667     }
5668   ret2->copyTinyInfoFrom(this);
5669   return ret2;
5670 }
5671
5672 /*!
5673  * This method returns a vector of size 'this->getNumberOfCells()'.
5674  * This method retrieves for each cell in 'this' if it is linear (false) or quadratic(true).
5675  */
5676 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const throw(INTERP_KERNEL::Exception)
5677 {
5678   int ncell=getNumberOfCells();
5679   std::vector<bool> ret(ncell);
5680   const int *cI=getNodalConnectivityIndex()->getConstPointer();
5681   const int *c=getNodalConnectivity()->getConstPointer();
5682   for(int i=0;i<ncell;i++)
5683     {
5684       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
5685       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5686       ret[i]=cm.isQuadratic();
5687     }
5688   return ret;
5689 }
5690
5691 /*!
5692  * Returns a newly created mesh (with ref count ==1) that contains merge of 'this' and 'other'.
5693  */
5694 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
5695 {
5696   if(other->getType()!=UNSTRUCTURED)
5697     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
5698   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
5699   return MergeUMeshes(this,otherC);
5700 }
5701
5702 /*!
5703  * Returns an array with this->getNumberOfCells() tuples and this->getSpaceDimension() dimension.
5704  * The false barycenter is computed that is to say barycenter of a cell is computed using average on each
5705  * components of coordinates of the cell.
5706  */
5707 DataArrayDouble *MEDCouplingUMesh::getBarycenterAndOwner() const
5708 {
5709   DataArrayDouble *ret=DataArrayDouble::New();
5710   int spaceDim=getSpaceDimension();
5711   int nbOfCells=getNumberOfCells();
5712   ret->alloc(nbOfCells,spaceDim);
5713   ret->copyStringInfoFrom(*getCoords());
5714   double *ptToFill=ret->getPointer();
5715   double *tmp=new double[spaceDim];
5716   const int *nodal=_nodal_connec->getConstPointer();
5717   const int *nodalI=_nodal_connec_index->getConstPointer();
5718   const double *coor=_coords->getConstPointer();
5719   for(int i=0;i<nbOfCells;i++)
5720     {
5721       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
5722       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
5723       ptToFill+=spaceDim;
5724     }
5725   delete [] tmp;
5726   return ret;
5727 }
5728
5729 /*!
5730  * This method is similar to MEDCouplingUMesh::getBarycenterAndOwner except that it works on subPart of 'this' without
5731  * 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().
5732  * No check of that will be done !
5733  */
5734 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
5735 {
5736   DataArrayDouble *ret=DataArrayDouble::New();
5737   int spaceDim=getSpaceDimension();
5738   int nbOfTuple=(int)std::distance(begin,end);
5739   ret->alloc(nbOfTuple,spaceDim);
5740   double *ptToFill=ret->getPointer();
5741   double *tmp=new double[spaceDim];
5742   const int *nodal=_nodal_connec->getConstPointer();
5743   const int *nodalI=_nodal_connec_index->getConstPointer();
5744   const double *coor=_coords->getConstPointer();
5745   for(const int *w=begin;w!=end;w++)
5746     {
5747       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
5748       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
5749       ptToFill+=spaceDim;
5750     }
5751   delete [] tmp;
5752   return ret;
5753 }
5754
5755 /*!
5756  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
5757  * 
5758  */
5759 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da) throw(INTERP_KERNEL::Exception)
5760 {
5761   if(!da)
5762     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
5763   da->checkAllocated();
5764   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName().c_str(),0);
5765   ret->setCoords(da);
5766   int nbOfTuples=da->getNumberOfTuples();
5767   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c=DataArrayInt::New();
5768   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cI=DataArrayInt::New();
5769   c->alloc(2*nbOfTuples,1);
5770   cI->alloc(nbOfTuples+1,1);
5771   int *cp=c->getPointer();
5772   int *cip=cI->getPointer();
5773   *cip++=0;
5774   for(int i=0;i<nbOfTuples;i++)
5775     {
5776       *cp++=INTERP_KERNEL::NORM_POINT1;
5777       *cp++=i;
5778       *cip++=2*(i+1);
5779     }
5780   ret->setConnectivity(c,cI,true);
5781   ret->incrRef();
5782   return ret;
5783 }
5784
5785 /*!
5786  * Returns a newly created mesh (with ref count ==1) that contains merge of 'mesh1' and 'other'.
5787  * The coords of 'mesh2' are added at the end of coords of 'mesh1'.
5788  */
5789 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception)
5790 {
5791   std::vector<const MEDCouplingUMesh *> tmp(2);
5792   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
5793   return MergeUMeshes(tmp);
5794 }
5795
5796 /*!
5797  * This method returns in case of success a mesh constitued from union of all meshes in 'a'.
5798  * There should be \b no presence of null pointer into 'a'. If any an INTERP_KERNEL::Exception will be thrown.
5799  * The returned mesh will contain aggregation of nodes in 'a' (in the same order) and aggregation of
5800  * cells in meshes in 'a' (in the same order too).
5801  */
5802 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a) throw(INTERP_KERNEL::Exception)
5803 {
5804   std::size_t sz=a.size();
5805   if(sz==0)
5806     return MergeUMeshesLL(a);
5807   for(std::size_t ii=0;ii<sz;ii++)
5808     if(!a[ii])
5809       {
5810         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
5811         throw INTERP_KERNEL::Exception(oss.str().c_str());
5812       }
5813   std::vector< MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> > bb(sz);
5814   std::vector< const MEDCouplingUMesh * > aa(sz);
5815   int spaceDim=-3;
5816   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
5817     {
5818       const MEDCouplingUMesh *cur=a[i];
5819       const DataArrayDouble *coo=cur->getCoords();
5820       if(coo)
5821         spaceDim=coo->getNumberOfComponents();
5822     }
5823   if(spaceDim==-3)
5824     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
5825   for(std::size_t i=0;i<sz;i++)
5826     {
5827       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
5828       aa[i]=bb[i];
5829     }
5830   return MergeUMeshesLL(aa);
5831 }
5832
5833 /// @cond INTERNAL
5834
5835 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a) throw(INTERP_KERNEL::Exception)
5836 {
5837   if(a.empty())
5838     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
5839   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
5840   int meshDim=(*it)->getMeshDimension();
5841   int nbOfCells=(*it)->getNumberOfCells();
5842   int meshLgth=(*it++)->getMeshLength();
5843   for(;it!=a.end();it++)
5844     {
5845       if(meshDim!=(*it)->getMeshDimension())
5846         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
5847       nbOfCells+=(*it)->getNumberOfCells();
5848       meshLgth+=(*it)->getMeshLength();
5849     }
5850   std::vector<const MEDCouplingPointSet *> aps(a.size());
5851   std::copy(a.begin(),a.end(),aps.begin());
5852   DataArrayDouble *pts=MergeNodesArray(aps);
5853   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
5854   ret->setCoords(pts);
5855   pts->decrRef();
5856   DataArrayInt *c=DataArrayInt::New();
5857   c->alloc(meshLgth,1);
5858   int *cPtr=c->getPointer();
5859   DataArrayInt *cI=DataArrayInt::New();
5860   cI->alloc(nbOfCells+1,1);
5861   int *cIPtr=cI->getPointer();
5862   *cIPtr++=0;
5863   int offset=0;
5864   int offset2=0;
5865   for(it=a.begin();it!=a.end();it++)
5866     {
5867       int curNbOfCell=(*it)->getNumberOfCells();
5868       const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
5869       const int *curC=(*it)->_nodal_connec->getConstPointer();
5870       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
5871       for(int j=0;j<curNbOfCell;j++)
5872         {
5873           const int *src=curC+curCI[j];
5874           *cPtr++=*src++;
5875           for(;src!=curC+curCI[j+1];src++,cPtr++)
5876             {
5877               if(*src!=-1)
5878                 *cPtr=*src+offset2;
5879               else
5880                 *cPtr=-1;
5881             }
5882         }
5883       offset+=curCI[curNbOfCell];
5884       offset2+=(*it)->getNumberOfNodes();
5885     }
5886   //
5887   ret->setConnectivity(c,cI,true);
5888   c->decrRef();
5889   cI->decrRef();
5890   ret->incrRef();
5891   return ret;
5892 }
5893
5894 /// @endcond
5895
5896 /*!
5897  * Idem MergeUMeshes except that 'meshes' are expected to lyie on the same coords and 'meshes' have the same meshdim.
5898  * 'meshes' must be a non empty vector.
5899  */
5900 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2) throw(INTERP_KERNEL::Exception)
5901 {
5902   std::vector<const MEDCouplingUMesh *> tmp(2);
5903   tmp[0]=mesh1; tmp[1]=mesh2;
5904   return MergeUMeshesOnSameCoords(tmp);
5905 }
5906
5907 /*!
5908  * Idem MergeUMeshes except that 'meshes' are expected to lyie on the same coords and 'meshes' have the same meshdim.
5909  * 'meshes' must be a non empty vector.
5910  */
5911 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
5912 {
5913   if(meshes.empty())
5914     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
5915   for(std::size_t ii=0;ii<meshes.size();ii++)
5916     if(!meshes[ii])
5917       {
5918         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
5919         throw INTERP_KERNEL::Exception(oss.str().c_str());
5920       }
5921   const DataArrayDouble *coords=meshes.front()->getCoords();
5922   int meshDim=meshes.front()->getMeshDimension();
5923   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
5924   int meshLgth=0;
5925   int meshIndexLgth=0;
5926   for(;iter!=meshes.end();iter++)
5927     {
5928       if(coords!=(*iter)->getCoords())
5929         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
5930       if(meshDim!=(*iter)->getMeshDimension())
5931         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
5932       meshLgth+=(*iter)->getMeshLength();
5933       meshIndexLgth+=(*iter)->getNumberOfCells();
5934     }
5935   DataArrayInt *nodal=DataArrayInt::New();
5936   nodal->alloc(meshLgth,1);
5937   int *nodalPtr=nodal->getPointer();
5938   DataArrayInt *nodalIndex=DataArrayInt::New();
5939   nodalIndex->alloc(meshIndexLgth+1,1);
5940   int *nodalIndexPtr=nodalIndex->getPointer();
5941   int offset=0;
5942   for(iter=meshes.begin();iter!=meshes.end();iter++)
5943     {
5944       const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
5945       const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
5946       int nbOfCells=(*iter)->getNumberOfCells();
5947       int meshLgth2=(*iter)->getMeshLength();
5948       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
5949       if(iter!=meshes.begin())
5950         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
5951       else
5952         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
5953       offset+=meshLgth2;
5954     }
5955   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
5956   ret->setName("merge");
5957   ret->setMeshDimension(meshDim);
5958   ret->setConnectivity(nodal,nodalIndex,true);
5959   ret->setCoords(coords);
5960   nodalIndex->decrRef();
5961   nodal->decrRef();
5962   return ret;
5963 }
5964
5965 /*!
5966  * This method fuses meshes 'meshes' and returns the fused mesh and the correspondances arrays for each mesh in 'meshes' in returned mesh.
5967  * 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)
5968  *
5969  * @param meshes input non empty vector containing meshes having same coordiantes array and same mesh dimension.
5970  * @param compType see MEDCouplingUMesh::zipConnectivityTraducer
5971  * @param corr output vector with same size as 'meshes' parameter. corr[i] is the correspondance array of mesh meshes[i] in returned mesh.
5972  *             The arrays contained in 'corr' parameter are returned with refcounter set to one.
5973  *             To avoid memory leaks the caller have to deal with each instances of DataArrayInt contained in 'corr' parameter.
5974  * @return The mesh lying on the same coordinates than those in meshes. All cells in 'meshes' are in returned mesh with 
5975  * @exception if meshes is a empty vector or meshes are not lying on same coordinates or meshes not have the same dimension.
5976  */
5977 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
5978 {
5979   //All checks are delegated to MergeUMeshesOnSameCoords
5980   MEDCouplingUMesh *ret=MergeUMeshesOnSameCoords(meshes);
5981   DataArrayInt *o2n=ret->zipConnectivityTraducer(compType);
5982   corr.resize(meshes.size());
5983   std::size_t nbOfMeshes=meshes.size();
5984   int offset=0;
5985   const int *o2nPtr=o2n->getConstPointer();
5986   for(std::size_t i=0;i<nbOfMeshes;i++)
5987     {
5988       DataArrayInt *tmp=DataArrayInt::New();
5989       int curNbOfCells=meshes[i]->getNumberOfCells();
5990       tmp->alloc(curNbOfCells,1);
5991       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
5992       offset+=curNbOfCells;
5993       tmp->setName(meshes[i]->getName());
5994       corr[i]=tmp;
5995     }
5996   o2n->decrRef();
5997   return ret;
5998 }
5999
6000 /*!
6001  * This method takes in input meshes \b meshes containing no null reference. If any an INTERP_KERNEL::Exception will be thrown.
6002  * \b meshes should have a good coherency (connectivity and coordinates well defined).
6003  * All mesh in \b meshes must have the same space dimension. If not an INTERP_KERNEL:Exception will be thrown.
6004  * But mesh in \b meshes \b can \b have \b different \b mesh \b dimension \b each \b other.
6005  *
6006  * This method performs nothing if size of \b meshes is in [0,1].
6007  * This method is particulary usefull in MEDLoader context to build a \ref ParaMEDMEM::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6008  * coordinates DataArrayDouble instance.
6009  *
6010  * \param [in,out] meshes : vector containing no null instance of MEDCouplingUMesh that in case of success of this method will be modified.
6011  */
6012 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes) throw(INTERP_KERNEL::Exception)
6013 {
6014   std::size_t sz=meshes.size();
6015   if(sz==0 || sz==1)
6016     return;
6017   std::vector< const DataArrayDouble * > coords(meshes.size());
6018   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6019   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6020     {
6021       if((*it))
6022         {
6023           (*it)->checkConnectivityFullyDefined();
6024           const DataArrayDouble *coo=(*it)->getCoords();
6025           if(coo)
6026             *it2=coo;
6027           else
6028             {
6029               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6030               oss << " has no coordinate array defined !";
6031               throw INTERP_KERNEL::Exception(oss.str().c_str());
6032             }
6033         }
6034       else
6035         {
6036           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6037           oss << " is null !";
6038           throw INTERP_KERNEL::Exception(oss.str().c_str());
6039         }
6040     }
6041   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6042   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6043   int offset=(*it)->getNumberOfNodes();
6044   (*it++)->setCoords(res);
6045   for(;it!=meshes.end();it++)
6046     {
6047       int oldNumberOfNodes=(*it)->getNumberOfNodes();
6048       (*it)->setCoords(res);
6049       (*it)->shiftNodeNumbersInConn(offset);
6050       offset+=oldNumberOfNodes;
6051     }
6052 }
6053
6054 /*!
6055  * This method takes in input meshes \b meshes containing no null reference. If any an INTERP_KERNEL::Exception will be thrown.
6056  * \b meshes should have a good coherency (connectivity and coordinates well defined).
6057  * All mesh in \b meshes must have the same space dimension. If not an INTERP_KERNEL:Exception will be thrown.
6058  * But mesh in \b meshes \b can \b have \b different \b mesh \b dimension \b each \b other.
6059  * 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.
6060  *
6061  * This method performs nothing if size of \b meshes is empty.
6062  * This method is particulary usefull in MEDLoader context to perform a treatment of a MEDFileUMesh instance on different levels.
6063  * coordinates DataArrayDouble instance.
6064  *
6065  * \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.
6066  * \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.
6067  */
6068 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps) throw(INTERP_KERNEL::Exception)
6069 {
6070   if(meshes.empty())
6071     return ;
6072   std::set<const DataArrayDouble *> s;
6073   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6074     {
6075       if(*it)
6076         s.insert((*it)->getCoords());
6077       else
6078         {
6079           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 !";
6080           throw INTERP_KERNEL::Exception(oss.str().c_str());
6081         }
6082     }
6083   if(s.size()!=1)
6084     {
6085       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 !";
6086       throw INTERP_KERNEL::Exception(oss.str().c_str());
6087     }
6088   const DataArrayDouble *coo=*(s.begin());
6089   if(!coo)
6090     return;
6091   //
6092   DataArrayInt *comm,*commI;
6093   coo->findCommonTuples(eps,-1,comm,commI);
6094   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp1(comm),tmp2(commI);
6095   int oldNbOfNodes=coo->getNumberOfTuples();
6096   int newNbOfNodes;
6097   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=DataArrayInt::BuildOld2NewArrayFromSurjectiveFormat2(oldNbOfNodes,comm,commI,newNbOfNodes);
6098   if(oldNbOfNodes==newNbOfNodes)
6099     return ;
6100   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
6101   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
6102     {
6103       (*it)->renumberNodesInConn(o2n->getConstPointer());
6104       (*it)->setCoords(newCoords);
6105     } 
6106 }
6107
6108 /*!
6109  * 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.
6110  * @param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
6111  * @param isQuad specifies the policy of connectivity.
6112  * @ret in/out parameter in which the result will be append
6113  */
6114 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
6115 {
6116   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
6117   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
6118   ret.push_back(cm.getExtrudedType());
6119   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
6120   switch(flatType)
6121     {
6122     case INTERP_KERNEL::NORM_POINT1:
6123       {
6124         ret.push_back(connBg[1]);
6125         ret.push_back(connBg[1]+nbOfNodesPerLev);
6126         break;
6127       }
6128     case INTERP_KERNEL::NORM_SEG2:
6129       {
6130         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
6131         ret.insert(ret.end(),conn,conn+4);
6132         break;
6133       }
6134     case INTERP_KERNEL::NORM_SEG3:
6135       {
6136         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
6137         ret.insert(ret.end(),conn,conn+8);
6138         break;
6139       }
6140     case INTERP_KERNEL::NORM_QUAD4:
6141       {
6142         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
6143         ret.insert(ret.end(),conn,conn+8);
6144         break;
6145       }
6146     case INTERP_KERNEL::NORM_TRI3:
6147       {
6148         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
6149         ret.insert(ret.end(),conn,conn+6);
6150         break;
6151       }
6152     case INTERP_KERNEL::NORM_TRI6:
6153       {
6154         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,
6155                       connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
6156         ret.insert(ret.end(),conn,conn+15);
6157         break;
6158       }
6159     case INTERP_KERNEL::NORM_QUAD8:
6160       {
6161         int conn[20]={
6162           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
6163           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
6164           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
6165         };
6166         ret.insert(ret.end(),conn,conn+20);
6167         break;
6168       }
6169     case INTERP_KERNEL::NORM_POLYGON:
6170       {
6171         std::back_insert_iterator< std::vector<int> > ii(ret);
6172         std::copy(connBg+1,connEnd,ii);
6173         *ii++=-1;
6174         std::reverse_iterator<const int *> rConnBg(connEnd);
6175         std::reverse_iterator<const int *> rConnEnd(connBg+1);
6176         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
6177         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
6178         for(std::size_t i=0;i<nbOfRadFaces;i++)
6179           {
6180             *ii++=-1;
6181             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
6182             std::copy(conn,conn+4,ii);
6183           }
6184         break;
6185       }
6186     default:
6187       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
6188     }
6189 }
6190
6191 /*!
6192  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [begin,end).
6193  */
6194 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
6195 {
6196   double v[3]={0.,0.,0.};
6197   std::size_t sz=std::distance(begin,end);
6198   if(isQuadratic)
6199     sz/=2;
6200   for(std::size_t i=0;i<sz;i++)
6201     {
6202       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];
6203       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
6204       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
6205     }
6206   return vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2]>0.;
6207 }
6208
6209 /*!
6210  * The polyhedron is specfied by its connectivity nodes in [begin,end).
6211  */
6212 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
6213 {
6214   std::vector<std::pair<int,int> > edges;
6215   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6216   const int *bgFace=begin;
6217   for(std::size_t i=0;i<nbOfFaces;i++)
6218     {
6219       const int *endFace=std::find(bgFace+1,end,-1);
6220       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6221       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
6222         {
6223           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
6224           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
6225             return false;
6226           edges.push_back(p1);
6227         }
6228       bgFace=endFace+1;
6229     }
6230   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
6231 }
6232
6233 /*!
6234  * 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) 
6235  * 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
6236  * a 2D space.
6237  *
6238  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
6239  * \param [in] coords the coordinates with nb of components exactly equal to 3
6240  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
6241  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
6242  * \param [out] the result is put at the end of the vector without any alteration of the data.
6243  */
6244 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, std::vector<int>& res) throw(INTERP_KERNEL::Exception)
6245 {
6246   int nbFaces=std::count(begin+1,end,-1)+1;
6247   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
6248   double *vPtr=v->getPointer();
6249   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
6250   double *pPtr=p->getPointer();
6251   const int *stFaceConn=begin+1;
6252   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
6253     {
6254       const int *endFaceConn=std::find(stFaceConn,end,-1);
6255       ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
6256       stFaceConn=endFaceConn+1;
6257     }
6258   pPtr=p->getPointer(); vPtr=v->getPointer();
6259   DataArrayInt *comm1=0,*commI1=0;
6260   v->findCommonTuples(eps,-1,comm1,commI1);
6261   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
6262   const int *comm1Ptr=comm1->getConstPointer();
6263   const int *commI1Ptr=commI1->getConstPointer();
6264   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
6265   res.push_back((int)INTERP_KERNEL::NORM_POLYHED);
6266   //
6267   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
6268   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
6269   mm->finishInsertingCells();
6270   //
6271   for(int i=0;i<nbOfGrps1;i++)
6272     {
6273       int vecId=comm1Ptr[commI1Ptr[i]];
6274       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6275       DataArrayInt *comm2=0,*commI2=0;
6276       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
6277       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
6278       const int *comm2Ptr=comm2->getConstPointer();
6279       const int *commI2Ptr=commI2->getConstPointer();
6280       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
6281       for(int j=0;j<nbOfGrps2;j++)
6282         {
6283           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
6284             {
6285               res.insert(res.end(),begin,end);
6286               res.push_back(-1);
6287             }
6288           else
6289             {
6290               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
6291               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids2=comm2->selectByTupleId2(commI2Ptr[j],commI2Ptr[j+1],1);
6292               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
6293               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
6294               MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
6295               MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
6296               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
6297               MEDCouplingAutoRefCountObjectPtr<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
6298               const int *idsNodePtr=idsNode->getConstPointer();
6299               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];
6300               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
6301               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
6302               if(std::abs(norm)>eps)
6303                 {
6304                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
6305                   mm3->rotate(center,vec,angle);
6306                 }
6307               mm3->changeSpaceDimension(2);
6308               MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
6309               const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
6310               const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
6311               int nbOfCells=mm4->getNumberOfCells();
6312               for(int k=0;k<nbOfCells;k++)
6313                 {
6314                   int l=0;
6315                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
6316                     res.push_back(idsNodePtr[*work]);
6317                   res.push_back(-1);
6318                 }
6319             }
6320         }
6321     }
6322   res.pop_back();
6323 }
6324
6325 /*!
6326  * 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
6327  * through origin. The plane is defined by its nodal connectivity [\b begin, \b end).
6328  * 
6329  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
6330  * \param [in] coords coordinates expected to have 3 components.
6331  * \param [in] begin start of the nodal connectivity of the face.
6332  * \param [in] end end of the nodal connectivity (excluded) of the face.
6333  * \param [out] v the normalized vector of size 3
6334  * \param [out] p the pos of plane
6335  */
6336 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p) throw(INTERP_KERNEL::Exception)
6337 {
6338   std::size_t nbPoints=std::distance(begin,end);
6339   if(nbPoints<3)
6340     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
6341   double vec[3];
6342   std::size_t j=0;
6343   bool refFound=false;
6344   for(;j<nbPoints-1 && !refFound;j++)
6345     {
6346       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
6347       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
6348       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
6349       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
6350       if(norm>eps)
6351         {
6352           refFound=true;
6353           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
6354         }
6355     }
6356   for(std::size_t i=j;i<nbPoints-1;i++)
6357     {
6358       double curVec[3];
6359       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
6360       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
6361       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
6362       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
6363       if(norm<eps)
6364         continue;
6365       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
6366       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];
6367       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
6368       if(norm>eps)
6369         {
6370           v[0]/=norm; v[1]/=norm; v[2]/=norm;
6371           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
6372           return ;
6373         }
6374     }
6375   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
6376 }
6377
6378 /*!
6379  * This method tries to obtain a well oriented polyhedron.
6380  * If the algorithm fails, an exception will be thrown.
6381  */
6382 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords) throw(INTERP_KERNEL::Exception)
6383 {
6384   std::vector<std::pair<int,int> > edges;
6385   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
6386   int *bgFace=begin;
6387   std::vector<bool> isPerm(nbOfFaces);
6388   for(std::size_t i=0;i<nbOfFaces;i++)
6389     {
6390       int *endFace=std::find(bgFace+1,end,-1);
6391       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6392       for(std::size_t l=0;l<nbOfEdgesInFace;l++)
6393         {
6394           std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]);
6395           edges.push_back(p1);
6396         }
6397       int *bgFace2=endFace+1;
6398       for(std::size_t k=i+1;k<nbOfFaces;k++)
6399         {
6400           int *endFace2=std::find(bgFace2+1,end,-1);
6401           std::size_t nbOfEdgesInFace2=std::distance(bgFace2,endFace2);
6402           for(std::size_t j=0;j<nbOfEdgesInFace2;j++)
6403             {
6404               std::pair<int,int> p2(bgFace2[j],bgFace2[(j+1)%nbOfEdgesInFace2]);
6405               if(std::find(edges.begin(),edges.end(),p2)!=edges.end())
6406                 {
6407                   if(isPerm[k])
6408                     throw INTERP_KERNEL::Exception("Fail to repare polyhedron ! Polyedron looks bad !");
6409                   std::vector<int> tmp(nbOfEdgesInFace2-1);
6410                   std::copy(bgFace2+1,endFace2,tmp.rbegin());
6411                   std::copy(tmp.begin(),tmp.end(),bgFace2+1);
6412                   isPerm[k]=true;
6413                   continue;
6414                 }
6415             }
6416           bgFace2=endFace2+1;
6417         }
6418       bgFace=endFace+1;
6419     }
6420   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
6421     {//not lucky ! The first face was not correctly oriented : reorient all faces...
6422       bgFace=begin;
6423       for(std::size_t i=0;i<nbOfFaces;i++)
6424         {
6425           int *endFace=std::find(bgFace+1,end,-1);
6426           std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
6427           std::vector<int> tmp(nbOfEdgesInFace-1);
6428           std::copy(bgFace+1,endFace,tmp.rbegin());
6429           std::copy(tmp.begin(),tmp.end(),bgFace+1);
6430           bgFace=endFace+1;
6431         }
6432     }
6433 }
6434
6435 /*!
6436  * This method makes the assumption spacedimension == meshdimension == 2.
6437  * This method works only for linear cells.
6438  * 
6439  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
6440  */
6441 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const throw(INTERP_KERNEL::Exception)
6442 {
6443   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
6444     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
6445   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=computeSkin();
6446   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> o2n=m->zipCoordsTraducer();
6447   int nbOfNodesExpected=m->getNumberOfNodes();
6448   if(m->getNumberOfCells()!=nbOfNodesExpected)
6449     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part or a quadratic 2D mesh !");
6450   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(m->getNumberOfNodes());
6451   const int *n2oPtr=n2o->getConstPointer();
6452   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
6453   m->getReverseNodalConnectivity(revNodal,revNodalI);
6454   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
6455   const int *nodalPtr=m->getNodalConnectivity()->getConstPointer();
6456   const int *nodalIPtr=m->getNodalConnectivityIndex()->getConstPointer();
6457   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(nbOfNodesExpected+1,1);
6458   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYGON;
6459   if(nbOfNodesExpected<1)
6460     { ret->incrRef(); return ret; }
6461   int prevCell=0;
6462   int prevNode=nodalPtr[nodalIPtr[0]+1];
6463   *work++=n2oPtr[prevNode];
6464   for(int i=1;i<nbOfNodesExpected;i++)
6465     {
6466       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
6467         {
6468           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
6469           conn.erase(prevNode);
6470           if(conn.size()==1)
6471             {
6472               int curNode=*(conn.begin());
6473               *work++=n2oPtr[curNode];
6474               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
6475               shar.erase(prevCell);
6476               if(shar.size()==1)
6477                 {
6478                   prevCell=*(shar.begin());
6479                   prevNode=curNode;
6480                 }
6481               else
6482                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected 2 !");
6483             }
6484           else
6485             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected 1 !");
6486         }
6487       else
6488         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : presence of unexpected cell !");
6489     }
6490   ret->incrRef(); return ret;
6491 }
6492
6493 /*!
6494  * This method makes the assumption spacedimension == meshdimension == 3.
6495  * This method works only for linear cells.
6496  * 
6497  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
6498  */
6499 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const throw(INTERP_KERNEL::Exception)
6500 {
6501   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6502     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
6503   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> m=computeSkin();
6504   const int *conn=m->getNodalConnectivity()->getConstPointer();
6505   const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
6506   int nbOfCells=m->getNumberOfCells();
6507   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
6508   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
6509   if(nbOfCells<1)
6510     { ret->incrRef(); return ret; }
6511   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
6512   for(int i=1;i<nbOfCells;i++)
6513     {
6514       *work++=-1;
6515       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
6516     }
6517   ret->incrRef();
6518   return ret;
6519 }
6520
6521 /*!
6522  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
6523  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
6524  */
6525 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt) throw(INTERP_KERNEL::Exception)
6526 {
6527   double *w=zipFrmt;
6528   if(spaceDim==3)
6529     for(int i=0;i<nbOfNodesInCell;i++)
6530       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
6531   else if(spaceDim==2)
6532     {
6533       for(int i=0;i<nbOfNodesInCell;i++)
6534         {
6535           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
6536           *w++=0.;
6537         }
6538     }
6539   else
6540     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
6541 }
6542
6543 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData) const throw(INTERP_KERNEL::Exception)
6544 {
6545   int nbOfCells=getNumberOfCells();
6546   if(nbOfCells<=0)
6547     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
6548   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};
6549   ofs << "  <" << getVTKDataSetType() << ">\n";
6550   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
6551   ofs << "      <PointData>\n" << pointData << std::endl;
6552   ofs << "      </PointData>\n";
6553   ofs << "      <CellData>\n" << cellData << std::endl;
6554   ofs << "      </CellData>\n";
6555   ofs << "      <Points>\n";
6556   if(getSpaceDimension()==3)
6557     _coords->writeVTK(ofs,8,"Points");
6558   else
6559     {
6560       MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
6561       coo->writeVTK(ofs,8,"Points");
6562     }
6563   ofs << "      </Points>\n";
6564   ofs << "      <Cells>\n";
6565   const int *cPtr=_nodal_connec->getConstPointer();
6566   const int *cIPtr=_nodal_connec_index->getConstPointer();
6567   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
6568   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
6569   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
6570   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
6571   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
6572   int szFaceOffsets=0,szConn=0;
6573   for(int i=0;i<nbOfCells;i++,w1++,w2++,*w3++)
6574     {
6575       *w2=cPtr[cIPtr[i]];
6576       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
6577         {
6578           *w1=-1;
6579           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
6580           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
6581         }
6582       else
6583         {
6584           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
6585           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
6586           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
6587           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
6588           w4=std::copy(c.begin(),c.end(),w4);
6589         }
6590     }
6591   types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE);
6592   types->writeVTK(ofs,8,"UInt8","types");
6593   offsets->writeVTK(ofs,8,"Int32","offsets");
6594   if(szFaceOffsets!=0)
6595     {//presence of Polyhedra
6596       connectivity->reAlloc(szConn);
6597       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets");
6598       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
6599       w1=faces->getPointer();
6600       for(int i=0;i<nbOfCells;i++)
6601         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
6602           {
6603             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
6604             *w1++=nbFaces;
6605             const int *w4=cPtr+cIPtr[i]+1,*w5=0;
6606             for(int j=0;j<nbFaces;j++)
6607               {
6608                 w5=std::find(w4,cPtr+cIPtr[i+1],-1);
6609                 *w1++=(int)std::distance(w4,w5);
6610                 w1=std::copy(w4,w5,w1);
6611                 w4=w5+1;
6612               }
6613           }
6614       faces->writeVTK(ofs,8,"Int32","faces");
6615     }
6616   connectivity->writeVTK(ofs,8,"Int32","connectivity");
6617   ofs << "      </Cells>\n";
6618   ofs << "    </Piece>\n";
6619   ofs << "  </" << getVTKDataSetType() << ">\n";
6620 }
6621
6622 std::string MEDCouplingUMesh::getVTKDataSetType() const throw(INTERP_KERNEL::Exception)
6623 {
6624   return std::string("UnstructuredGrid");
6625 }
6626
6627 /// @cond INTERNAL
6628
6629 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2) throw(INTERP_KERNEL::Exception)
6630 {
6631   m1->checkFullyDefined();
6632   m2->checkFullyDefined();
6633   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
6634     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
6635   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
6636   MEDCouplingUMesh *m1Desc=0,*m2Desc=0;
6637   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
6638   std::vector<double> addCoo,addCoordsQuadratic;
6639   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
6640   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
6641   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
6642                               m2Desc,desc2,descIndx2,revDesc2,revDescIndx2,addCoo);
6643   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
6644   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
6645   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
6646   std::vector< std::vector<int> > intersectEdge2;
6647   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
6648   subDiv2.clear(); dd5=0; dd6=0;
6649   std::vector<int> cr,crI;
6650   std::vector<int> cNb1,cNb2;
6651   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
6652                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
6653   //
6654   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> addCooDa=DataArrayDouble::New();
6655   addCooDa->alloc((int)(addCoo.size())/2,2);
6656   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
6657   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> addCoordsQuadraticDa=DataArrayDouble::New();
6658   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
6659   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
6660   std::vector<const DataArrayDouble *> coordss(4);
6661   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
6662   MEDCouplingAutoRefCountObjectPtr<DataArrayDouble> coo=DataArrayDouble::Aggregate(coordss);
6663   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Intersect2D",2);
6664   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> conn=DataArrayInt::New(); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
6665   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> connI=DataArrayInt::New(); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
6666   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c1=DataArrayInt::New(); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer()); cellNb1=c1;
6667   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> c2=DataArrayInt::New(); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer()); cellNb2=c2;
6668   ret->setConnectivity(conn,connI,true);
6669   ret->setCoords(coo);
6670   ret->incrRef(); c1->incrRef(); c2->incrRef();
6671   return ret;
6672 }
6673
6674 /// @endcond
6675
6676 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
6677                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
6678                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
6679                                                          const std::vector<double>& addCoords,
6680                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
6681 {
6682   static const int SPACEDIM=2;
6683   std::vector<double> bbox1,bbox2;
6684   const double *coo1=m1->getCoords()->getConstPointer();
6685   const int *conn1=m1->getNodalConnectivity()->getConstPointer();
6686   const int *connI1=m1->getNodalConnectivityIndex()->getConstPointer();
6687   int offset1=m1->getNumberOfNodes();
6688   const double *coo2=m2->getCoords()->getConstPointer();
6689   const int *conn2=m2->getNodalConnectivity()->getConstPointer();
6690   const int *connI2=m2->getNodalConnectivityIndex()->getConstPointer();
6691   int offset2=offset1+m2->getNumberOfNodes();
6692   int offset3=offset2+((int)addCoords.size())/2;
6693   m1->getBoundingBoxForBBTree(bbox1);
6694   m2->getBoundingBoxForBBTree(bbox2);
6695   BBTree<SPACEDIM,int> myTree(&bbox2[0],0,0,m2->getNumberOfCells(),eps);
6696   int ncell1=m1->getNumberOfCells();
6697   crI.push_back(0);
6698   for(int i=0;i<ncell1;i++)
6699     {
6700       std::vector<int> candidates2;
6701       myTree.getIntersectingElems(&bbox1[i*2*SPACEDIM],candidates2);
6702       std::map<INTERP_KERNEL::Node *,int> mapp;
6703       std::map<int,INTERP_KERNEL::Node *> mappRev;
6704       INTERP_KERNEL::QuadraticPolygon pol1;
6705       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
6706       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6707       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
6708       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
6709                                    desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
6710       std::vector<int> crTmp,crITmp;
6711       crITmp.push_back(crI.back());
6712       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++)
6713         {
6714           INTERP_KERNEL::QuadraticPolygon pol2;
6715           pol1.initLocations();
6716           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
6717           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
6718           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
6719           pol2.buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
6720                                         pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
6721           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
6722           pol1.buildPartitionsAbs(pol2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
6723         }
6724       if(!crTmp.empty())
6725         {
6726           cr.insert(cr.end(),crTmp.begin(),crTmp.end());
6727           crI.insert(crI.end(),crITmp.begin()+1,crITmp.end());
6728         }
6729       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
6730         (*it).second->decrRef();
6731     }
6732 }
6733
6734 /*!
6735  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
6736  * 
6737  */
6738 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
6739                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
6740                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
6741                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2,
6742                                                    std::vector<double>& addCoo) throw(INTERP_KERNEL::Exception)
6743 {
6744   static const int SPACEDIM=2;
6745   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
6746   desc2=DataArrayInt::New();
6747   descIndx2=DataArrayInt::New();
6748   revDesc2=DataArrayInt::New();
6749   revDescIndx2=DataArrayInt::New();
6750   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
6751   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
6752   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
6753   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
6754   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
6755   const int *c1=m1Desc->getNodalConnectivity()->getConstPointer();
6756   const int *ci1=m1Desc->getNodalConnectivityIndex()->getConstPointer();
6757   std::vector<double> bbox1,bbox2;
6758   m1Desc->getBoundingBoxForBBTree(bbox1);
6759   m2Desc->getBoundingBoxForBBTree(bbox2);
6760   int ncell1=m1Desc->getNumberOfCells();
6761   int ncell2=m2Desc->getNumberOfCells();
6762   intersectEdge1.resize(ncell1);
6763   colinear2.resize(ncell2);
6764   subDiv2.resize(ncell2);
6765   BBTree<SPACEDIM,int> myTree(&bbox2[0],0,0,m2Desc->getNumberOfCells(),-eps);
6766   std::vector<int> candidates1(1);
6767   int offset1=m1->getNumberOfNodes();
6768   int offset2=offset1+m2->getNumberOfNodes();
6769   for(int i=0;i<ncell1;i++)
6770     {
6771       std::vector<int> candidates2;
6772       myTree.getIntersectingElems(&bbox1[i*2*SPACEDIM],candidates2);
6773       if(!candidates2.empty())
6774         {
6775           std::map<INTERP_KERNEL::Node *,int> map1,map2;
6776           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
6777           candidates1[0]=i;
6778           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
6779           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo);
6780           delete pol2;
6781           delete pol1;
6782         }
6783       else
6784         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i+1]);
6785     }
6786   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
6787   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
6788 }
6789
6790 /*!
6791  * This method performs the 2nd step of Partition of 2D mesh.
6792  * This method has 4 inputs :
6793  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
6794  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
6795  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids in randomly sorted.
6796  * 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'
6797  * @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'
6798  * @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.
6799  * @param addCoo input parameter with additionnal nodes linked to intersection of the 2 meshes.
6800  */
6801 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)
6802 {
6803   int offset1=m1->getNumberOfNodes();
6804   int ncell=m2->getNumberOfCells();
6805   const int *c=m2->getNodalConnectivity()->getConstPointer();
6806   const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
6807   const double *coo=m2->getCoords()->getConstPointer();
6808   const double *cooBis=m1->getCoords()->getConstPointer();
6809   int offset2=offset1+m2->getNumberOfNodes();
6810   intersectEdge.resize(ncell);
6811   for(int i=0;i<ncell;i++,cI++)
6812     {
6813       const std::vector<int>& divs=subDiv[i];
6814       int nnode=cI[1]-cI[0]-1;
6815       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
6816       std::map<INTERP_KERNEL::Node *, int> mapp22;
6817       for(int j=0;j<nnode;j++)
6818         {
6819           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
6820           int nnid=c[(*cI)+j+1];
6821           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
6822           mapp22[nn]=nnid+offset1;
6823         }
6824       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
6825       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
6826         ((*it).second.first)->decrRef();
6827       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
6828       std::map<INTERP_KERNEL::Node *,int> mapp3;
6829       for(std::size_t j=0;j<divs.size();j++)
6830         {
6831           int id=divs[j];
6832           INTERP_KERNEL::Node *tmp=0;
6833           if(id<offset1)
6834             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
6835           else if(id<offset2)
6836             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
6837           else
6838             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
6839           addNodes[j]=tmp;
6840           mapp3[tmp]=id;
6841         }
6842       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
6843       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
6844         (*it)->decrRef();
6845       e->decrRef();
6846     }
6847 }
6848
6849 /*!
6850  * 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).
6851  * 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
6852  * with a plane. The result will be put in 'cut3DSuf' out parameter.
6853  * @param cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
6854  * @param nodesOnPlane, returns all the nodes that are on the plane.
6855  * @param nodal3DSurf is the nodal connectivity of 3D surf mesh.
6856  * @param nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
6857  * @param nodal3DCurve is the nodal connectivity of 3D curve mesh.
6858  * @param nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
6859  * @param desc is the descending connectivity 3DSurf->3DCurve
6860  * @param descIndx is the descending connectivity index 3DSurf->3DCurve
6861  * @param cut3DSuf input/output param.
6862  */
6863 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
6864                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
6865                                                    const int *desc, const int *descIndx, 
6866                                                    std::vector< std::pair<int,int> >& cut3DSurf) throw(INTERP_KERNEL::Exception)
6867 {
6868   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
6869   int nbOf3DSurfCell=(int)cut3DSurf.size();
6870   for(int i=0;i<nbOf3DSurfCell;i++)
6871     {
6872       std::vector<int> res;
6873       int offset=descIndx[i];
6874       int nbOfSeg=descIndx[i+1]-offset;
6875       for(int j=0;j<nbOfSeg;j++)
6876         {
6877           int edgeId=desc[offset+j];
6878           int status=cut3DCurve[edgeId];
6879           if(status!=-2)
6880             {
6881               if(status>-1)
6882                 res.push_back(status);
6883               else
6884                 {
6885                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
6886                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
6887                 }
6888             }
6889         }
6890       switch(res.size())
6891         {
6892         case 2:
6893           {
6894             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
6895             break;
6896           }
6897         case 1:
6898         case 0:
6899           {
6900             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
6901             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
6902             if(res.size()==2)
6903               {
6904                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
6905               }
6906             else
6907               {
6908                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
6909               }
6910             break;
6911           }
6912         default:
6913           {// case when plane is on a multi colinear edge of a polyhedron
6914             if((int)res.size()==2*nbOfSeg)
6915               {
6916                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
6917               }
6918             else
6919               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
6920           }
6921         }
6922     }
6923 }
6924
6925 /*!
6926  * 'this' is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
6927  * 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).
6928  * 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
6929  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
6930  * @param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
6931  * @param desc is the descending connectivity 3D->3DSurf
6932  * @param descIndx is the descending connectivity index 3D->3DSurf
6933  */
6934 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
6935                                                   const int *desc, const int *descIndx,
6936                                                   std::vector<int>& nodalRes, std::vector<int>& nodalResIndx, std::vector<int>& cellIds) const throw(INTERP_KERNEL::Exception)
6937 {
6938   checkFullyDefined();
6939   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6940     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
6941   const int *nodal3D=_nodal_connec->getConstPointer();
6942   const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
6943   int nbOfCells=getNumberOfCells();
6944   for(int i=0;i<nbOfCells;i++)
6945     {
6946       std::map<int, std::set<int> > m;
6947       int offset=descIndx[i];
6948       int nbOfFaces=descIndx[i+1]-offset;
6949       int start=-1;
6950       int end=-1;
6951       for(int j=0;j<nbOfFaces;j++)
6952         {
6953           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
6954           if(p.first!=-1 && p.second!=-1)
6955             {
6956               if(p.first!=-2)
6957                 {
6958                   start=p.first; end=p.second;
6959                   m[p.first].insert(p.second);
6960                   m[p.second].insert(p.first);
6961                 }
6962               else
6963                 {
6964                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
6965                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
6966                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
6967                   INTERP_KERNEL::NormalizedCellType cmsId;
6968                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
6969                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
6970                   for(unsigned k=0;k<nbOfNodesSon;k++)
6971                     {
6972                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
6973                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
6974                     }
6975                 }
6976             }
6977         }
6978       if(m.empty())
6979         continue;
6980       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
6981       int prev=end;
6982       while(end!=start)
6983         {
6984           std::map<int, std::set<int> >::const_iterator it=m.find(start);
6985           const std::set<int>& s=(*it).second;
6986           std::set<int> s2; s2.insert(prev);
6987           std::set<int> s3;
6988           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
6989           if(s3.size()==1)
6990             {
6991               int val=*s3.begin();
6992               conn.push_back(start);
6993               prev=start;
6994               start=val;
6995             }
6996           else
6997             start=end;
6998         }
6999       conn.push_back(end);
7000       if(conn.size()>3)
7001         {
7002           nodalRes.insert(nodalRes.end(),conn.begin(),conn.end());
7003           nodalResIndx.push_back((int)nodalRes.size());
7004           cellIds.push_back(i);
7005         }
7006     }
7007 }
7008
7009 /*!
7010  * 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
7011  * 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
7012  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7013  * 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
7014  * 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.
7015  * 
7016  * @return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7017  */
7018 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, std::vector<int>& nodalConnecOut) throw(INTERP_KERNEL::Exception)
7019 {
7020   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7021   if(sz>=4)
7022     {
7023       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7024       if(cm.getDimension()==2)
7025         {
7026           const int *node=nodalConnBg+1;
7027           int startNode=*node++;
7028           double refX=coords[2*startNode];
7029           for(;node!=nodalConnEnd;node++)
7030             {
7031               if(coords[2*(*node)]<refX)
7032                 {
7033                   startNode=*node;
7034                   refX=coords[2*startNode];
7035                 }
7036             }
7037           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7038           refX=1e300;
7039           double tmp1;
7040           double tmp2[2];
7041           double angle0=-M_PI/2;
7042           //
7043           int nextNode=-1;
7044           int prevNode=-1;
7045           double resRef;
7046           double angleNext;
7047           while(nextNode!=startNode)
7048             {
7049               nextNode=-1;
7050               resRef=1e300;
7051               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7052                 {
7053                   if(*node!=tmpOut.back() && *node!=prevNode)
7054                     {
7055                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7056                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7057                       double res;
7058                       if(angleM<=angle0)
7059                         res=angle0-angleM;
7060                       else
7061                         res=angle0-angleM+2.*M_PI;
7062                       if(res<resRef)
7063                         {
7064                           nextNode=*node;
7065                           resRef=res;
7066                           angleNext=angleM;
7067                         }
7068                     }
7069                 }
7070               if(nextNode!=startNode)
7071                 {
7072                   angle0=angleNext-M_PI;
7073                   if(angle0<-M_PI)
7074                     angle0+=2*M_PI;
7075                   prevNode=tmpOut.back();
7076                   tmpOut.push_back(nextNode);
7077                 }
7078             }
7079           std::vector<int> tmp3(2*(sz-1));
7080           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7081           std::copy(nodalConnBg+1,nodalConnEnd,it);
7082           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7083             {
7084               nodalConnecOut.insert(nodalConnecOut.end(),nodalConnBg,nodalConnEnd);
7085               return false;
7086             }
7087           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7088             {
7089               nodalConnecOut.insert(nodalConnecOut.end(),nodalConnBg,nodalConnEnd);
7090               return false;
7091             }
7092           else
7093             {
7094               nodalConnecOut.push_back((int)INTERP_KERNEL::NORM_POLYGON);
7095               nodalConnecOut.insert(nodalConnecOut.end(),tmpOut.begin(),tmpOut.end());
7096               return true;
7097             }
7098         }
7099     }
7100   else
7101     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7102 }
7103
7104 /*!
7105  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
7106  * 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.
7107  * 
7108  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
7109  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
7110  * \param [in,out] arr array in which the remove operation will be done.
7111  * \param [in,out] arrIndx array in the remove operation will modify
7112  * \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])
7113  * \return true if \b arr and \b arrIndx have been modified, false if not.
7114  */
7115 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval) throw(INTERP_KERNEL::Exception)
7116 {
7117   if(!arrIndx || !arr)
7118     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
7119   if(offsetForRemoval<0)
7120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
7121   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
7122   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
7123   int *arrIPtr=arrIndx->getPointer();
7124   *arrIPtr++=0;
7125   int previousArrI=0;
7126   const int *arrPtr=arr->getConstPointer();
7127   std::vector<int> arrOut;
7128   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
7129     {
7130       if(*arrIPtr-previousArrI>offsetForRemoval)
7131         {
7132           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
7133             {
7134               if(s.find(*work)==s.end())
7135                 arrOut.push_back(*work);
7136             }
7137         }
7138       previousArrI=*arrIPtr;
7139       *arrIPtr=(int)arrOut.size();
7140     }
7141   if(arr->getNumberOfTuples()==(int)arrOut.size())
7142     return false;
7143   arr->alloc((int)arrOut.size(),1);
7144   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
7145   return true;
7146 }
7147
7148 /*!
7149  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7150  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
7151  * The selection of extraction is done standardly in new2old format.
7152  * This method returns indexed arrays using 2 arrays (arrOut,arrIndexOut).
7153  *
7154  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7155  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7156  * \param [in] arrIn arr origin array from which the extraction will be done.
7157  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7158  * \param [out] arrOut the resulting array
7159  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7160  */
7161 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7162                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7163 {
7164   if(!arrIn || !arrIndxIn)
7165     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7166   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
7167   const int *arrInPtr=arrIn->getConstPointer();
7168   const int *arrIndxPtr=arrIndxIn->getConstPointer();
7169   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
7170   int maxSizeOfArr=arrIn->getNumberOfTuples();
7171   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7172   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7173   arrIo->alloc((int)(sz+1),1);
7174   const int *idsIt=idsOfSelectBg;
7175   int *work=arrIo->getPointer();
7176   *work++=0;
7177   int lgth=0;
7178   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
7179     {
7180       if(*idsIt>=0 && *idsIt<nbOfGrps)
7181         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
7182       else
7183         {
7184           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
7185           throw INTERP_KERNEL::Exception(oss.str().c_str());
7186         }
7187       if(lgth>=work[-1])
7188         *work=lgth;
7189       else
7190         {
7191           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
7192           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
7193           throw INTERP_KERNEL::Exception(oss.str().c_str());
7194         }
7195     }
7196   arro->alloc(lgth,1);
7197   work=arro->getPointer();
7198   idsIt=idsOfSelectBg;
7199   for(std::size_t i=0;i<sz;i++,idsIt++)
7200     {
7201       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
7202         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
7203       else
7204         {
7205           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
7206           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
7207           throw INTERP_KERNEL::Exception(oss.str().c_str());
7208         }
7209     }
7210   arrOut=arro;
7211   arrIndexOut=arrIo;
7212   arro->incrRef();
7213   arrIo->incrRef();
7214 }
7215
7216 /*!
7217  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7218  * 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
7219  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7220  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7221  *
7222  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7223  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7224  * \param [in] arrIn arr origin array from which the extraction will be done.
7225  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7226  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7227  * \param [in] srcArrIndex index array of \b srcArr
7228  * \param [out] arrOut the resulting array
7229  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7230  * 
7231  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7232  */
7233 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7234                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7235                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7236 {
7237   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7238     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
7239   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7240   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7241   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7242   std::vector<bool> v(nbOfTuples,true);
7243   int offset=0;
7244   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7245   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7246   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7247     {
7248       if(*it>=0 && *it<nbOfTuples)
7249         {
7250           v[*it]=false;
7251           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
7252         }
7253       else
7254         {
7255           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7256           throw INTERP_KERNEL::Exception(oss.str().c_str());
7257         }
7258     }
7259   srcArrIndexPtr=srcArrIndex->getConstPointer();
7260   arrIo->alloc(nbOfTuples+1,1);
7261   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7262   const int *arrInPtr=arrIn->getConstPointer();
7263   const int *srcArrPtr=srcArr->getConstPointer();
7264   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7265   int *arroPtr=arro->getPointer();
7266   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7267     {
7268       if(v[ii])
7269         {
7270           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7271           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7272         }
7273       else
7274         {
7275           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
7276           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7277           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7278         }
7279     }
7280   arrOut=arro; arro->incrRef();
7281   arrIndexOut=arrIo; arrIo->incrRef();
7282 }
7283
7284 /*!
7285  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7286  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7287  *
7288  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
7289  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
7290  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7291  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7292  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7293  * \param [in] srcArrIndex index array of \b srcArr
7294  * 
7295  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
7296  */
7297 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7298                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex) throw(INTERP_KERNEL::Exception)
7299 {
7300   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7301     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
7302   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7303   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7304   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7305   int *arrInOutPtr=arrInOut->getPointer();
7306   const int *srcArrPtr=srcArr->getConstPointer();
7307   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
7308     {
7309       if(*it>=0 && *it<nbOfTuples)
7310         {
7311           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
7312             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
7313           else
7314             {
7315               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] !";
7316               throw INTERP_KERNEL::Exception(oss.str().c_str());
7317             }
7318         }
7319       else
7320         {
7321           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
7322           throw INTERP_KERNEL::Exception(oss.str().c_str());
7323         }
7324     }
7325 }
7326
7327 /*!
7328  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7329  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7330  * 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]].
7331  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7332  * A negative value in \b arrIn means that it is ignored.
7333  * 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.
7334  * 
7335  * \param [in] arrIn arr origin array from which the extraction will be done.
7336  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7337  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7338  */
7339 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn) throw(INTERP_KERNEL::Exception)
7340 {
7341   if(!arrIn || !arrIndxIn)
7342     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
7343   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7344   if(nbOfTuples<=0)
7345     {
7346       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
7347       return ret;
7348     }
7349   const int *arrInPtr=arrIn->getConstPointer();
7350   const int *arrIndxPtr=arrIndxIn->getConstPointer();
7351   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7352   arro->alloc(nbOfTuples,1);
7353   arro->fillWithValue(-1);
7354   int *arroPtr=arro->getPointer();
7355   std::set<int> s; s.insert(0);
7356   while(!s.empty())
7357     {
7358       std::set<int> s2;
7359       for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7360         {
7361           for(const int *work=arrInPtr+arrIndxPtr[*it];work!=arrInPtr+arrIndxPtr[*it+1];work++)
7362             {
7363               if(*work>=0 && arroPtr[*work]<0)
7364                 {
7365                   arroPtr[*work]=1;
7366                   s2.insert(*work);
7367                 }
7368             }
7369         }
7370       s=s2;
7371     }
7372   return arro->getIdsEqual(1);
7373 }
7374
7375 /*!
7376  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7377  * 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
7378  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
7379  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
7380  *
7381  * \param [in] start begin of set of ids of the input extraction (included)
7382  * \param [in] end end of set of ids of the input extraction (excluded)
7383  * \param [in] step step of the set of ids in range mode.
7384  * \param [in] arrIn arr origin array from which the extraction will be done.
7385  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7386  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7387  * \param [in] srcArrIndex index array of \b srcArr
7388  * \param [out] arrOut the resulting array
7389  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
7390  * 
7391  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
7392  */
7393 void MEDCouplingUMesh::SetPartOfIndexedArrays2(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
7394                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
7395                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut) throw(INTERP_KERNEL::Exception)
7396 {
7397   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7398     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays2 : presence of null pointer in input parameter !");
7399   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arro=DataArrayInt::New();
7400   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> arrIo=DataArrayInt::New();
7401   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7402   int offset=0;
7403   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7404   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7405   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArrays2 : ");
7406   int it=start;
7407   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7408     {
7409       if(it>=0 && it<nbOfTuples)
7410         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
7411       else
7412         {
7413           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays2 : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
7414           throw INTERP_KERNEL::Exception(oss.str().c_str());
7415         }
7416     }
7417   srcArrIndexPtr=srcArrIndex->getConstPointer();
7418   arrIo->alloc(nbOfTuples+1,1);
7419   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
7420   const int *arrInPtr=arrIn->getConstPointer();
7421   const int *srcArrPtr=srcArr->getConstPointer();
7422   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
7423   int *arroPtr=arro->getPointer();
7424   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
7425     {
7426       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
7427       if(pos<0)
7428         {
7429           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
7430           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
7431         }
7432       else
7433         {
7434           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
7435           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
7436         }
7437     }
7438   arrOut=arro; arro->incrRef();
7439   arrIndexOut=arrIo; arrIo->incrRef();
7440 }
7441
7442 /*!
7443  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
7444  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
7445  *
7446  * \param [in] start begin of set of ids of the input extraction (included)
7447  * \param [in] end end of set of ids of the input extraction (excluded)
7448  * \param [in] step step of the set of ids in range mode.
7449  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
7450  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7451  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
7452  * \param [in] srcArrIndex index array of \b srcArr
7453  * 
7454  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays2 MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
7455  */
7456 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
7457                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex) throw(INTERP_KERNEL::Exception)
7458 {
7459   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
7460     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : presence of null pointer in input parameter !");
7461   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7462   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
7463   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
7464   int *arrInOutPtr=arrInOut->getPointer();
7465   const int *srcArrPtr=srcArr->getConstPointer();
7466   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : ");
7467   int it=start;
7468   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
7469     {
7470       if(it>=0 && it<nbOfTuples)
7471         {
7472           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
7473             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
7474           else
7475             {
7476               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
7477               throw INTERP_KERNEL::Exception(oss.str().c_str());
7478             }
7479         }
7480       else
7481         {
7482           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx2 : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
7483           throw INTERP_KERNEL::Exception(oss.str().c_str());
7484         }
7485     }
7486 }
7487
7488 /*!
7489  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7490  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7491  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7492  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7493  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7494  * 
7495  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7496  */
7497 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const throw(INTERP_KERNEL::Exception)
7498 {
7499   checkFullyDefined();
7500   int mdim=getMeshDimension();
7501   int spaceDim=getSpaceDimension();
7502   if(mdim!=spaceDim)
7503     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7504   int nbCells=getNumberOfCells();
7505   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
7506   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
7507   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > >(partitionAuto));
7508   MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7509   ret->setCoords(getCoords());
7510   ret->allocateCells((int)partition.size());
7511   //
7512   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
7513     {
7514       MEDCouplingAutoRefCountObjectPtr<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7515       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> cell;
7516       switch(mdim)
7517         {
7518         case 2:
7519           cell=tmp->buildUnionOf2DMesh();
7520           break;
7521         case 3:
7522           cell=tmp->buildUnionOf3DMesh();
7523           break;
7524         default:
7525           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7526         }
7527       
7528       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
7529     }
7530   //
7531   ret->finishInsertingCells();
7532   ret->incrRef(); return ret;
7533 }
7534
7535 /*!
7536  * This method partitions \b this into contiguous zone.
7537  * This method only needs a well defined connectivity. Coordinates are not considered here.
7538  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7539  */
7540 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const throw(INTERP_KERNEL::Exception)
7541 {
7542   int nbOfCellsCur=getNumberOfCells();
7543   DataArrayInt *neigh=0,*neighI=0;
7544   computeNeighborsOfCells(neigh,neighI);
7545   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
7546   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ids=DataArrayInt::New(); ids->alloc(nbOfCellsCur,1); ids->iota();
7547   std::vector<DataArrayInt *> ret;
7548   std::vector< MEDCouplingAutoRefCountObjectPtr<DataArrayInt> > ret2;
7549   while(nbOfCellsCur>0)
7550     {
7551       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp=MEDCouplingUMesh::ComputeSpreadZoneGradually(neighAuto,neighIAuto);
7552       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp3=tmp->buildComplement(nbOfCellsCur);
7553       MEDCouplingAutoRefCountObjectPtr<DataArrayInt> tmp2=ids->selectByTupleId(tmp->begin(),tmp->end());
7554       ret2.push_back(tmp2);  ret.push_back(tmp2);
7555       nbOfCellsCur=tmp3->getNumberOfTuples();
7556       if(nbOfCellsCur>0)
7557         {
7558           ids=ids->selectByTupleId(tmp3->begin(),tmp3->end());
7559           MEDCouplingUMesh::ExtractFromIndexedArrays(tmp3->begin(),tmp3->end(),neighAuto,neighIAuto,neigh,neighI);
7560           neighAuto=neigh;
7561           neighIAuto=neighI;
7562           MEDCouplingAutoRefCountObjectPtr<DataArrayInt> renum=tmp3->invertArrayN2O2O2N(nbOfCellsCur+tmp->getNumberOfTuples());
7563           neighAuto->transformWithIndArr(renum->begin(),renum->end());
7564         }
7565     }
7566   for(std::vector<DataArrayInt *>::const_iterator it=ret.begin();it!=ret.end();it++)
7567     (*it)->incrRef();
7568   return ret;
7569 }
7570
7571 /*!
7572  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
7573  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
7574  *
7575  * \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.
7576  * \return a newly allocated DataArrayInt to be managed by the caller.
7577  * \throw In case of \a code has not the right format (typically of size 3*n)
7578  */
7579 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code) throw(INTERP_KERNEL::Exception)
7580 {
7581   MEDCouplingAutoRefCountObjectPtr<DataArrayInt> ret=DataArrayInt::New();
7582   std::size_t nb=code.size()/3;
7583   if(code.size()%3!=0)
7584     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
7585   ret->alloc((int)nb,2);
7586   int *retPtr=ret->getPointer();
7587   for(std::size_t i=0;i<nb;i++,retPtr+=2)
7588     {
7589       retPtr[0]=code[3*i+2];
7590       retPtr[1]=code[3*i+2]+code[3*i+1];
7591     }
7592   ret->incrRef();
7593   return ret;
7594 }
7595
7596 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
7597                                                                                    _own_cell(true),_cell_id(-1),_nb_cell(0)
7598 {
7599   if(mesh)
7600     {
7601       mesh->incrRef();
7602       _nb_cell=mesh->getNumberOfCells();
7603     }
7604 }
7605
7606 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
7607 {
7608   if(_mesh)
7609     _mesh->decrRef();
7610   if(_own_cell)
7611     delete _cell;
7612 }
7613
7614 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
7615                                                                                                                                _own_cell(false),_cell_id(bg-1),
7616                                                                                                                                _nb_cell(end)
7617 {
7618   if(mesh)
7619     mesh->incrRef();
7620 }
7621
7622 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
7623 {
7624   _cell_id++;
7625   if(_cell_id<_nb_cell)
7626     {
7627       _cell->next();
7628       return _cell;
7629     }
7630   else
7631     return 0;
7632 }
7633
7634 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
7635 {
7636   if(_mesh)
7637     _mesh->incrRef();
7638 }
7639
7640 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
7641 {
7642   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
7643 }
7644
7645 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
7646 {
7647   if(_mesh)
7648     _mesh->decrRef();
7649 }
7650
7651 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
7652                                                                                                                                                                   _itc(itc),
7653                                                                                                                                                                   _bg(bg),_end(end)
7654 {
7655   if(_mesh)
7656     _mesh->incrRef();
7657 }
7658
7659 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
7660 {
7661   if(_mesh)
7662     _mesh->decrRef();
7663 }
7664
7665 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
7666 {
7667   return _type;
7668 }
7669
7670 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
7671 {
7672   return _end-_bg;
7673 }
7674
7675 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
7676 {
7677   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
7678 }
7679
7680 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
7681 {
7682   if(mesh)
7683     {
7684       mesh->incrRef();
7685       _nb_cell=mesh->getNumberOfCells();
7686     }
7687 }
7688
7689 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
7690 {
7691   if(_mesh)
7692     _mesh->decrRef();
7693   delete _cell;
7694 }
7695
7696 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
7697 {
7698   const int *c=_mesh->getNodalConnectivity()->getConstPointer();
7699   const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
7700   if(_cell_id<_nb_cell)
7701     {
7702       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
7703       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,ParaMEDMEMImpl::ConnReader(c,type)));
7704       int startId=_cell_id;
7705       _cell_id+=nbOfElems;
7706       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
7707     }
7708   else
7709     return 0;
7710 }
7711
7712 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
7713 {
7714   if(mesh)
7715     {
7716       _conn=mesh->getNodalConnectivity()->getPointer();
7717       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
7718     }
7719 }
7720
7721 void MEDCouplingUMeshCell::next()
7722 {
7723   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7724     {
7725       _conn+=_conn_lgth;
7726       _conn_indx++;
7727     }
7728   _conn_lgth=_conn_indx[1]-_conn_indx[0];
7729 }
7730
7731 std::string MEDCouplingUMeshCell::repr() const
7732 {
7733   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7734     {
7735       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
7736       oss << " : ";
7737       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
7738       return oss.str();
7739     }
7740   else
7741     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
7742 }
7743
7744 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
7745 {
7746   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7747     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
7748   else
7749     return INTERP_KERNEL::NORM_ERROR;
7750 }
7751
7752 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
7753 {
7754   lgth=_conn_lgth;
7755   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
7756     return _conn;
7757   else
7758     return 0;
7759 }