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