Salome HOME
5da2235bcd8daf681d9908f27b026dc3020823d6
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingFieldDouble.hxx"
24 #include "MEDCouplingSkyLineArray.hxx"
25 #include "CellModel.hxx"
26 #include "VolSurfUser.txx"
27 #include "InterpolationUtils.hxx"
28 #include "PointLocatorAlgos.txx"
29 #include "BBTree.txx"
30 #include "BBTreeDst.txx"
31 #include "SplitterTetra.hxx"
32 #include "DiameterCalculator.hxx"
33 #include "DirectedBoundingBox.hxx"
34 #include "InterpKernelMatrixTools.hxx"
35 #include "InterpKernelMeshQuality.hxx"
36 #include "InterpKernelCellSimplify.hxx"
37 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
38 #include "InterpKernelAutoPtr.hxx"
39 #include "InterpKernelGeo2DNode.hxx"
40 #include "InterpKernelGeo2DEdgeLin.hxx"
41 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
42 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
43
44 #include <sstream>
45 #include <fstream>
46 #include <numeric>
47 #include <cstring>
48 #include <limits>
49 #include <list>
50
51 using namespace MEDCoupling;
52
53 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
54
55 /// @cond INTERNAL
56 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 };
57 const int MEDCouplingUMesh::MEDCOUPLING2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
58 /// @endcond
59
60 MEDCouplingUMesh *MEDCouplingUMesh::New()
61 {
62   return new MEDCouplingUMesh;
63 }
64
65 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
66 {
67   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
68   ret->setName(meshName);
69   ret->setMeshDimension(meshDim);
70   return ret;
71 }
72
73 /*!
74  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
75  * between \a this and the new mesh.
76  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
77  *          delete this mesh using decrRef() as it is no more needed. 
78  */
79 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
80 {
81   return clone(true);
82 }
83
84
85 /*!
86  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
87  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
88  * this mesh are shared by the new mesh.
89  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
90  *          delete this mesh using decrRef() as it is no more needed. 
91  */
92 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
93 {
94   return new MEDCouplingUMesh(*this,recDeepCpy);
95 }
96
97 /*!
98  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
99  * The coordinates are shared between \a this and the returned instance.
100  * 
101  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
102  * \sa MEDCouplingUMesh::deepCopy
103  */
104 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
105 {
106   checkConnectivityFullyDefined();
107   MCAuto<MEDCouplingUMesh> ret=clone(false);
108   MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
109   ret->setConnectivity(c,ci);
110   return ret.retn();
111 }
112
113 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
114 {
115   if(!other)
116     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
117   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
118   if(!otherC)
119     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
120   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
121   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
122 }
123
124 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
125 {
126   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
127   return ret;
128 }
129
130 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
131 {
132   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
133   ret.push_back(_nodal_connec);
134   ret.push_back(_nodal_connec_index);
135   return ret;
136 }
137
138 void MEDCouplingUMesh::updateTime() const
139 {
140   MEDCouplingPointSet::updateTime();
141   if(_nodal_connec)
142     {
143       updateTimeWith(*_nodal_connec);
144     }
145   if(_nodal_connec_index)
146     {
147       updateTimeWith(*_nodal_connec_index);
148     }
149 }
150
151 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
152 {
153 }
154
155 /*!
156  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
157  * then \a this mesh is most probably is writable, exchangeable and available for most
158  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
159  * this method to check that all is in order with \a this mesh.
160  *  \throw If the mesh dimension is not set.
161  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
162  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
163  *  \throw If the connectivity data array has more than one component.
164  *  \throw If the connectivity data array has a named component.
165  *  \throw If the connectivity index data array has more than one component.
166  *  \throw If the connectivity index data array has a named component.
167  */
168 void MEDCouplingUMesh::checkConsistencyLight() const
169 {
170   if(_mesh_dim<-1)
171     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
172   if(_mesh_dim!=-1)
173     MEDCouplingPointSet::checkConsistencyLight();
174   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
175     {
176       if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
177         {
178           std::ostringstream message;
179           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
180           throw INTERP_KERNEL::Exception(message.str().c_str());
181         }
182     }
183   if(_nodal_connec)
184     {
185       if(_nodal_connec->getNumberOfComponents()!=1)
186         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
187       if(_nodal_connec->getInfoOnComponent(0)!="")
188         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
189     }
190   else
191     if(_mesh_dim!=-1)
192       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
193   if(_nodal_connec_index)
194     {
195       if(_nodal_connec_index->getNumberOfComponents()!=1)
196         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
197       if(_nodal_connec_index->getInfoOnComponent(0)!="")
198         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
199     }
200   else
201     if(_mesh_dim!=-1)
202       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
203 }
204
205 /*!
206  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
207  * then \a this mesh is most probably is writable, exchangeable and available for all
208  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
209  * method thoroughly checks the nodal connectivity.
210  *  \param [in] eps - a not used parameter.
211  *  \throw If the mesh dimension is not set.
212  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
213  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
214  *  \throw If the connectivity data array has more than one component.
215  *  \throw If the connectivity data array has a named component.
216  *  \throw If the connectivity index data array has more than one component.
217  *  \throw If the connectivity index data array has a named component.
218  *  \throw If number of nodes defining an element does not correspond to the type of element.
219  *  \throw If the nodal connectivity includes an invalid node id.
220  */
221 void MEDCouplingUMesh::checkConsistency(double eps) const
222 {
223   checkConsistencyLight();
224   if(_mesh_dim==-1)
225     return ;
226   int meshDim=getMeshDimension();
227   int nbOfNodes=getNumberOfNodes();
228   int nbOfCells=getNumberOfCells();
229   const int *ptr=_nodal_connec->getConstPointer();
230   const int *ptrI=_nodal_connec_index->getConstPointer();
231   for(int i=0;i<nbOfCells;i++)
232     {
233       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
234       if((int)cm.getDimension()!=meshDim)
235         {
236           std::ostringstream oss;
237           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
238           throw INTERP_KERNEL::Exception(oss.str());
239         }
240       int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
241       if(!cm.isDynamic())
242         if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
243           {
244             std::ostringstream oss;
245             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
246             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
247             throw INTERP_KERNEL::Exception(oss.str());
248           }
249       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
250         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
254             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
258         {
259           int nodeId=*w;
260           if(nodeId>=0)
261             {
262               if(nodeId>=nbOfNodes)
263                 {
264                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
265                   throw INTERP_KERNEL::Exception(oss.str());
266                 }
267             }
268           else if(nodeId<-1)
269             {
270               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
271               throw INTERP_KERNEL::Exception(oss.str());
272             }
273           else
274             {
275               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
276                 {
277                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
278                   throw INTERP_KERNEL::Exception(oss.str());
279                 }
280             }
281         }
282     }
283 }
284
285 /*!
286  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
287  * elements contained in the mesh. For more info on the mesh dimension see
288  * \ref MEDCouplingUMeshPage.
289  *  \param [in] meshDim - a new mesh dimension.
290  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
291  */
292 void MEDCouplingUMesh::setMeshDimension(int meshDim)
293 {
294   if(meshDim<-1 || meshDim>3)
295     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
296   _mesh_dim=meshDim;
297   declareAsNew();
298 }
299
300 /*!
301  * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
302  * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
303  * If a nodal connectivity previouly existed before the call of this method, it will be reset.
304  *
305  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
306  *
307  *  \if ENABLE_EXAMPLES
308  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
309  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
310  *  \endif
311  */
312 void MEDCouplingUMesh::allocateCells(int nbOfCells)
313 {
314   if(nbOfCells<0)
315     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
316   if(_nodal_connec_index)
317     {
318       _nodal_connec_index->decrRef();
319     }
320   if(_nodal_connec)
321     {
322       _nodal_connec->decrRef();
323     }
324   _nodal_connec_index=DataArrayInt::New();
325   _nodal_connec_index->reserve(nbOfCells+1);
326   _nodal_connec_index->pushBackSilent(0);
327   _nodal_connec=DataArrayInt::New();
328   _nodal_connec->reserve(2*nbOfCells);
329   _types.clear();
330   declareAsNew();
331 }
332
333 /*!
334  * Appends a cell to the connectivity array. For deeper understanding what is
335  * happening see \ref MEDCouplingUMeshNodalConnectivity.
336  *  \param [in] type - type of cell to add.
337  *  \param [in] size - number of nodes constituting this cell.
338  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
339  * 
340  *  \if ENABLE_EXAMPLES
341  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
342  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
343  *  \endif
344  */
345 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
346 {
347   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
348   if(_nodal_connec_index==0)
349     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
350   if((int)cm.getDimension()==_mesh_dim)
351     {
352       if(!cm.isDynamic())
353         if(size!=(int)cm.getNumberOfNodes())
354           {
355             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
356             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
357             throw INTERP_KERNEL::Exception(oss.str());
358           }
359       int idx=_nodal_connec_index->back();
360       int val=idx+size+1;
361       _nodal_connec_index->pushBackSilent(val);
362       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
363       _types.insert(type);
364     }
365   else
366     {
367       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
368       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
369       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
370       throw INTERP_KERNEL::Exception(oss.str());
371     }
372 }
373
374 /*!
375  * Compacts data arrays to release unused memory. This method is to be called after
376  * finishing cell insertion using \a this->insertNextCell().
377  * 
378  *  \if ENABLE_EXAMPLES
379  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
380  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
381  *  \endif
382  */
383 void MEDCouplingUMesh::finishInsertingCells()
384 {
385   _nodal_connec->pack();
386   _nodal_connec_index->pack();
387   _nodal_connec->declareAsNew();
388   _nodal_connec_index->declareAsNew();
389   updateTime();
390 }
391
392 /*!
393  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
394  * Useful for python users.
395  */
396 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
397 {
398   return new MEDCouplingUMeshCellIterator(this);
399 }
400
401 /*!
402  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
403  * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
404  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
405  * Useful for python users.
406  */
407 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
408 {
409   if(!checkConsecutiveCellTypes())
410     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
411   return new MEDCouplingUMeshCellByTypeEntry(this);
412 }
413
414 /*!
415  * Returns a set of all cell types available in \a this mesh.
416  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
417  * \warning this method does not throw any exception even if \a this is not defined.
418  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
419  */
420 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
421 {
422   return _types;
423 }
424
425 /*!
426  * This method returns the sorted list of geometric types in \a this.
427  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
428  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
429  *
430  * \throw if connectivity in \a this is not correctly defined.
431  *  
432  * \sa MEDCouplingMesh::getAllGeoTypes
433  */
434 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
435 {
436   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
437   checkConnectivityFullyDefined();
438   int nbOfCells(getNumberOfCells());
439   if(nbOfCells==0)
440     return ret;
441   if(getNodalConnectivityArrayLen()<1)
442     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
443   const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
444   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
445   for(int i=1;i<nbOfCells;i++,ci++)
446     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
447       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
448   return ret;
449 }
450
451 /*!
452  * This method is a method that compares \a this and \a other.
453  * This method compares \b all attributes, even names and component names.
454  */
455 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
456 {
457   if(!other)
458     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
459   std::ostringstream oss; oss.precision(15);
460   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
461   if(!otherC)
462     {
463       reason="mesh given in input is not castable in MEDCouplingUMesh !";
464       return false;
465     }
466   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
467     return false;
468   if(_mesh_dim!=otherC->_mesh_dim)
469     {
470       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
471       reason=oss.str();
472       return false;
473     }
474   if(_types!=otherC->_types)
475     {
476       oss << "umesh geometric type mismatch :\nThis geometric types are :";
477       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
478         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
479       oss << "\nOther geometric types are :";
480       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
481         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
482       reason=oss.str();
483       return false;
484     }
485   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
486     if(_nodal_connec==0 || otherC->_nodal_connec==0)
487       {
488         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
489         return false;
490       }
491   if(_nodal_connec!=otherC->_nodal_connec)
492     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
493       {
494         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
495         return false;
496       }
497   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
498     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
499       {
500         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
501         return false;
502       }
503   if(_nodal_connec_index!=otherC->_nodal_connec_index)
504     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
505       {
506         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
507         return false;
508       }
509   return true;
510 }
511
512 /*!
513  * Checks if data arrays of this mesh (node coordinates, nodal
514  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
515  * not considered.
516  *  \param [in] other - the mesh to compare with.
517  *  \param [in] prec - precision value used to compare node coordinates.
518  *  \return bool - \a true if the two meshes are same.
519  */
520 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
521 {
522   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
523   if(!otherC)
524     return false;
525   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
526     return false;
527   if(_mesh_dim!=otherC->_mesh_dim)
528     return false;
529   if(_types!=otherC->_types)
530     return false;
531   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
532     if(_nodal_connec==0 || otherC->_nodal_connec==0)
533       return false;
534   if(_nodal_connec!=otherC->_nodal_connec)
535     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
536       return false;
537   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
538     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
539       return false;
540   if(_nodal_connec_index!=otherC->_nodal_connec_index)
541     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
542       return false;
543   return true;
544 }
545
546 /*!
547  * Checks if \a this and \a other meshes are geometrically equivalent with high
548  * probability, else an exception is thrown. The meshes are considered equivalent if
549  * (1) meshes contain the same number of nodes and the same number of elements of the
550  * same types (2) three cells of the two meshes (first, last and middle) are based
551  * on coincident nodes (with a specified precision).
552  *  \param [in] other - the mesh to compare with.
553  *  \param [in] prec - the precision used to compare nodes of the two meshes.
554  *  \throw If the two meshes do not match.
555  */
556 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
557 {
558   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
559   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
560   if(!otherC)
561     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !"); 
562 }
563
564 /*!
565  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
566  * cells each node belongs to.
567  * \warning For speed reasons, this method does not check if node ids in the nodal
568  *          connectivity correspond to the size of node coordinates array.
569  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
570  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
571  *        dividing cell ids in \a revNodal into groups each referring to one
572  *        node. Its every element (except the last one) is an index pointing to the
573  *         first id of a group of cells. For example cells sharing the node #1 are 
574  *        described by following range of indices: 
575  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
576  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
577  *        Number of cells sharing the *i*-th node is
578  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
579  * \throw If the coordinates array is not set.
580  * \throw If the nodal connectivity of cells is not defined.
581  * 
582  * \if ENABLE_EXAMPLES
583  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
584  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
585  * \endif
586  */
587 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
588 {
589   checkFullyDefined();
590   int nbOfNodes=getNumberOfNodes();
591   int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
592   revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
593   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
594   const int *conn=_nodal_connec->getConstPointer();
595   const int *connIndex=_nodal_connec_index->getConstPointer();
596   int nbOfCells=getNumberOfCells();
597   int nbOfEltsInRevNodal=0;
598   for(int eltId=0;eltId<nbOfCells;eltId++)
599     {
600       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
601       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
602       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
603         if(*iter>=0)//for polyhedrons
604           {
605             nbOfEltsInRevNodal++;
606             revNodalIndxPtr[(*iter)+1]++;
607           }
608     }
609   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
610   int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
611   revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
612   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
613   for(int eltId=0;eltId<nbOfCells;eltId++)
614     {
615       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
616       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
617       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
618         if(*iter>=0)//for polyhedrons
619           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
620     }
621 }
622
623 /// @cond INTERNAL
624
625 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
626 {
627   return id;
628 }
629
630 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
631 {
632   if(!compute)
633     return id+1;
634   else
635     {
636       if(cm.getOrientationStatus(nb,conn1,conn2))
637         return id+1;
638       else
639         return -(id+1);
640     }
641 }
642
643 class MinusOneSonsGenerator
644 {
645 public:
646   MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
647   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
648   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
649   static const int DELTA=1;
650 private:
651   const INTERP_KERNEL::CellModel& _cm;
652 };
653
654 class MinusOneSonsGeneratorBiQuadratic
655 {
656 public:
657   MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
658   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
659   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
660   static const int DELTA=1;
661 private:
662   const INTERP_KERNEL::CellModel& _cm;
663 };
664
665 class MinusTwoSonsGenerator
666 {
667 public:
668   MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
669   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
670   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
671   static const int DELTA=2;
672 private:
673   const INTERP_KERNEL::CellModel& _cm;
674 };
675
676 class MicroEdgesGenerator2D
677 {
678 public:
679   MicroEdgesGenerator2D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
680   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
681   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
682   static const int DELTA=1;
683 private:
684   const INTERP_KERNEL::CellModel& _cm;
685 };
686
687 class MicroEdgesGenerator3D
688 {
689 public:
690   MicroEdgesGenerator3D(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
691   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfMicroEdges(); }
692   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillMicroEdgeNodalConnectivity(sonId,nodalConn,sonNodalConn,typeOfSon); }
693   static const int DELTA=2;
694 private:
695   const INTERP_KERNEL::CellModel& _cm;
696 };
697
698 /// @endcond
699
700 /*!
701  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
702  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
703  * describing correspondence between cells of \a this and the result meshes are
704  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
705  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
706  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
707  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh. 
708  * \warning For speed reasons, this method does not check if node ids in the nodal
709  *          connectivity correspond to the size of node coordinates array.
710  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
711  *          to write this mesh to the MED file, its cells must be sorted using
712  *          sortCellsInMEDFileFrmt().
713  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
714  *         each cell of \a this mesh.
715  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
716  *        dividing cell ids in \a desc into groups each referring to one
717  *        cell of \a this mesh. Its every element (except the last one) is an index
718  *        pointing to the first id of a group of cells. For example cells of the
719  *        result mesh bounding the cell #1 of \a this mesh are described by following
720  *        range of indices:
721  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
722  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
723  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
724  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
725  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
726  *         by each cell of the result mesh.
727  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
728  *        in the result mesh,
729  *        dividing cell ids in \a revDesc into groups each referring to one
730  *        cell of the result mesh the same way as \a descIndx divides \a desc.
731  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
732  *        delete this mesh using decrRef() as it is no more needed.
733  *  \throw If the coordinates array is not set.
734  *  \throw If the nodal connectivity of cells is node defined.
735  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
736  *         revDescIndx == NULL.
737  * 
738  *  \if ENABLE_EXAMPLES
739  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
740  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
741  *  \endif
742  * \sa buildDescendingConnectivity2()
743  */
744 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
745 {
746   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
747 }
748
749 /*!
750  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
751  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
752  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
753  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
754  * \sa MEDCouplingUMesh::buildDescendingConnectivity
755  */
756 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
757 {
758   checkFullyDefined();
759   if(getMeshDimension()!=3)
760     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
761   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
762 }
763
764 /*!
765  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
766  * This method works for both meshes with mesh dimenstion equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
767  * 
768  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
769  */
770 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
771 {
772    checkFullyDefined();
773    switch(getMeshDimension())
774      {
775      case 2:
776        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
777      case 3:
778        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
779      default:
780        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
781      }
782 }
783
784 /*!
785  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
786  * this->getMeshDimension(), that bound cells of \a this mesh. In
787  * addition arrays describing correspondence between cells of \a this and the result
788  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
789  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
790  *  mesh. This method differs from buildDescendingConnectivity() in that apart
791  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
792  * result meshes. So a positive id means that order of nodes in corresponding cells
793  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
794  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
795  * i.e. cell ids are one-based.
796  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
797  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh. 
798  * \warning For speed reasons, this method does not check if node ids in the nodal
799  *          connectivity correspond to the size of node coordinates array.
800  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
801  *          to write this mesh to the MED file, its cells must be sorted using
802  *          sortCellsInMEDFileFrmt().
803  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
804  *         each cell of \a this mesh.
805  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
806  *        dividing cell ids in \a desc into groups each referring to one
807  *        cell of \a this mesh. Its every element (except the last one) is an index
808  *        pointing to the first id of a group of cells. For example cells of the
809  *        result mesh bounding the cell #1 of \a this mesh are described by following
810  *        range of indices:
811  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
812  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
813  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
814  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
815  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
816  *         by each cell of the result mesh.
817  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
818  *        in the result mesh,
819  *        dividing cell ids in \a revDesc into groups each referring to one
820  *        cell of the result mesh the same way as \a descIndx divides \a desc.
821  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
822  *        shares the node coordinates array with \a this mesh. The caller is to
823  *        delete this mesh using decrRef() as it is no more needed.
824  *  \throw If the coordinates array is not set.
825  *  \throw If the nodal connectivity of cells is node defined.
826  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
827  *         revDescIndx == NULL.
828  * 
829  *  \if ENABLE_EXAMPLES
830  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
831  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
832  *  \endif
833  * \sa buildDescendingConnectivity()
834  */
835 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
836 {
837   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
838 }
839
840 /*!
841  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
842  * For speed reasons no check of this will be done. This method calls
843  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
844  * This method lists cell by cell in \b this which are its neighbors. To compute the result
845  * only connectivities are considered.
846  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
847  * The format of return is hence \ref numbering-indirect.
848  *
849  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
850  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
851  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
852  * is equal to the last values in \b neighborsIndx.
853  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
854  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
855  */
856 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
857 {
858   MCAuto<DataArrayInt> desc=DataArrayInt::New();
859   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
860   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
861   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
862   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
863   meshDM1=0;
864   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
865 }
866
867 /*!
868  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
869  * of MEDCouplingUMesh::computeNeighborsOfCells.
870  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
871  * typically the case to extract a set a neighbours,
872  * excluding a set of meshdim-1 cells in input descending connectivity.
873  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
874  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
875  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
876  * are considered.
877  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
878  *
879  * \param [in] desc descending connectivity array.
880  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
881  * \param [in] revDesc reverse descending connectivity array.
882  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
883  * \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
884  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
885  * \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.
886  */
887 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
888                                                   DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
889 {
890   if(!desc || !descIndx || !revDesc || !revDescIndx)
891     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
892   const int *descPtr=desc->getConstPointer();
893   const int *descIPtr=descIndx->getConstPointer();
894   const int *revDescPtr=revDesc->getConstPointer();
895   const int *revDescIPtr=revDescIndx->getConstPointer();
896   //
897   int nbCells=descIndx->getNumberOfTuples()-1;
898   MCAuto<DataArrayInt> out0=DataArrayInt::New();
899   MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
900   int *out1Ptr=out1->getPointer();
901   *out1Ptr++=0;
902   out0->reserve(desc->getNumberOfTuples());
903   for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
904     {
905       for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
906         {
907           std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
908           s.erase(i);
909           out0->insertAtTheEnd(s.begin(),s.end());
910         }
911       *out1Ptr=out0->getNumberOfTuples();
912     }
913   neighbors=out0.retn();
914   neighborsIndx=out1.retn();
915 }
916
917 /*!
918  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
919  * For speed reasons no check of this will be done. This method calls
920  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
921  * This method lists node by node in \b this which are its neighbors. To compute the result
922  * only connectivities are considered.
923  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
924  *
925  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
926  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
927  * parameter allows to select the right part in this array (\ref numbering-indirect).
928  * The number of tuples is equal to the last values in \b neighborsIndx.
929  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
930  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
931  */
932 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
933 {
934   checkFullyDefined();
935   int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
936   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
937   MCAuto<MEDCouplingUMesh> mesh1D;
938   switch(mdim)
939   {
940     case 3:
941       {
942         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
943         break;
944       }
945     case 2:
946       {
947         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
948         break;
949       }
950     case 1:
951       {
952         mesh1D=const_cast<MEDCouplingUMesh *>(this);
953         mesh1D->incrRef();
954         break;
955       }
956     default:
957       {
958         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
959       }
960   }
961   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
962   mesh1D->getReverseNodalConnectivity(desc,descIndx);
963   MCAuto<DataArrayInt> ret0(DataArrayInt::New());
964   ret0->alloc(desc->getNumberOfTuples(),1);
965   int *r0Pt(ret0->getPointer());
966   const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
967   for(int i=0;i<nbNodes;i++,rni++)
968     {
969       for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
970         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
971     }
972   neighbors=ret0.retn();
973   neighborsIdx=descIndx.retn();
974 }
975
976 /// @cond INTERNAL
977
978 /*!
979  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
980  * For speed reasons no check of this will be done.
981  */
982 template<class SonsGenerator>
983 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
984 {
985   if(!desc || !descIndx || !revDesc || !revDescIndx)
986     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
987   checkConnectivityFullyDefined();
988   int nbOfCells=getNumberOfCells();
989   int nbOfNodes=getNumberOfNodes();
990   MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
991   int *revNodalIndxPtr=revNodalIndx->getPointer();
992   const int *conn=_nodal_connec->getConstPointer();
993   const int *connIndex=_nodal_connec_index->getConstPointer();
994   std::string name="Mesh constituent of "; name+=getName();
995   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
996   ret->setCoords(getCoords());
997   ret->allocateCells(2*nbOfCells);
998   descIndx->alloc(nbOfCells+1,1);
999   MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
1000   int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
1001   for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
1002     {
1003       int pos=connIndex[eltId];
1004       int posP1=connIndex[eltId+1];
1005       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
1006       SonsGenerator sg(cm);
1007       unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
1008       INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
1009       for(unsigned i=0;i<nbOfSons;i++)
1010         {
1011           INTERP_KERNEL::NormalizedCellType cmsId;
1012           unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
1013           for(unsigned k=0;k<nbOfNodesSon;k++)
1014             if(tmp[k]>=0)
1015               revNodalIndxPtr[tmp[k]+1]++;
1016           ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
1017           revDesc2->pushBackSilent(eltId);
1018         }
1019       descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
1020     }
1021   int nbOfCellsM1=ret->getNumberOfCells();
1022   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
1023   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
1024   std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
1025   int *revNodalPtr=revNodal->getPointer();
1026   const int *connM1=ret->getNodalConnectivity()->getConstPointer();
1027   const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
1028   for(int eltId=0;eltId<nbOfCellsM1;eltId++)
1029     {
1030       const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
1031       const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
1032       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
1033         if(*iter>=0)//for polyhedrons
1034           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
1035     }
1036   //
1037   DataArrayInt *commonCells=0,*commonCellsI=0;
1038   FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
1039   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1040   const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
1041   int newNbOfCellsM1=-1;
1042   MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1043                                                                                                             commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1044   std::vector<bool> isImpacted(nbOfCellsM1,false);
1045   for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1046     for(int work2=work[0];work2!=work[1];work2++)
1047       isImpacted[commonCellsPtr[work2]]=true;
1048   const int *o2nM1Ptr=o2nM1->getConstPointer();
1049   MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1050   const int *n2oM1Ptr=n2oM1->getConstPointer();
1051   MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1052   ret2->copyTinyInfoFrom(this);
1053   desc->alloc(descIndx->back(),1);
1054   int *descPtr=desc->getPointer();
1055   const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1056   for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1057     {
1058       if(!isImpacted[i])
1059         *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1060       else
1061         {
1062           if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1063             {
1064               const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1065               *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1066             }
1067           else
1068             *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1069         }
1070     }
1071   revDesc->reserve(newNbOfCellsM1);
1072   revDescIndx->alloc(newNbOfCellsM1+1,1);
1073   int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1074   const int *revDesc2Ptr=revDesc2->getConstPointer();
1075   for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1076     {
1077       int oldCellIdM1=n2oM1Ptr[i];
1078       if(!isImpacted[oldCellIdM1])
1079         {
1080           revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1081           revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1082         }
1083       else
1084         {
1085           for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1086             revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1087           revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1088           commonCellsIPtr++;
1089         }
1090     }
1091   //
1092   return ret2.retn();
1093 }
1094
1095 struct MEDCouplingAccVisit
1096 {
1097   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1098   int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1099   int _new_nb_of_nodes;
1100 };
1101
1102 /// @endcond
1103
1104 /*!
1105  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1106  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1107  * array of cell ids. Pay attention that after conversion all algorithms work slower
1108  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1109  * conversion due presence of invalid ids in the array of cells to convert, as a
1110  * result \a this mesh contains some already converted elements. In this case the 2D
1111  * mesh remains valid but 3D mesh becomes \b inconsistent!
1112  *  \warning This method can significantly modify the order of geometric types in \a this,
1113  *          hence, to write this mesh to the MED file, its cells must be sorted using
1114  *          sortCellsInMEDFileFrmt().
1115  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1116  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1117  *         cellIdsToConvertBg.
1118  *  \throw If the coordinates array is not set.
1119  *  \throw If the nodal connectivity of cells is node defined.
1120  *  \throw If dimension of \a this mesh is not either 2 or 3.
1121  *
1122  *  \if ENABLE_EXAMPLES
1123  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1124  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1125  *  \endif
1126  */
1127 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1128 {
1129   checkFullyDefined();
1130   int dim=getMeshDimension();
1131   if(dim<2 || dim>3)
1132     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1133   int nbOfCells(getNumberOfCells());
1134   if(dim==2)
1135     {
1136       const int *connIndex=_nodal_connec_index->getConstPointer();
1137       int *conn=_nodal_connec->getPointer();
1138       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1139         {
1140           if(*iter>=0 && *iter<nbOfCells)
1141             {
1142               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1143               if(!cm.isQuadratic())
1144                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1145               else
1146                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1147             }
1148           else
1149             {
1150               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1151               oss << " in range [0," << nbOfCells << ") !";
1152               throw INTERP_KERNEL::Exception(oss.str());
1153             }
1154         }
1155     }
1156   else
1157     {
1158       int *connIndex(_nodal_connec_index->getPointer());
1159       const int *connOld(_nodal_connec->getConstPointer());
1160       MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1161       std::vector<bool> toBeDone(nbOfCells,false);
1162       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1163         {
1164           if(*iter>=0 && *iter<nbOfCells)
1165             toBeDone[*iter]=true;
1166           else
1167             {
1168               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1169               oss << " in range [0," << nbOfCells << ") !";
1170               throw INTERP_KERNEL::Exception(oss.str());
1171             }
1172         }
1173       for(int cellId=0;cellId<nbOfCells;cellId++)
1174         {
1175           int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1176           int lgthOld(posP1-pos-1);
1177           if(toBeDone[cellId])
1178             {
1179               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1180               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1181               int *tmp(new int[nbOfFaces*lgthOld+1]);
1182               int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1183               for(unsigned j=0;j<nbOfFaces;j++)
1184                 {
1185                   INTERP_KERNEL::NormalizedCellType type;
1186                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1187                   work+=offset;
1188                   *work++=-1;
1189                 }
1190               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1191               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1192               connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1193               delete [] tmp;
1194             }
1195           else
1196             {
1197               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1198               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1199             }
1200         }
1201       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1202     }
1203   computeTypes();
1204 }
1205
1206 /*!
1207  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1208  * polyhedrons (if \a this is a 3D mesh).
1209  *  \warning As this method is purely for user-friendliness and no optimization is
1210  *          done to avoid construction of a useless vector, this method can be costly
1211  *          in memory.
1212  *  \throw If the coordinates array is not set.
1213  *  \throw If the nodal connectivity of cells is node defined.
1214  *  \throw If dimension of \a this mesh is not either 2 or 3.
1215  */
1216 void MEDCouplingUMesh::convertAllToPoly()
1217 {
1218   int nbOfCells=getNumberOfCells();
1219   std::vector<int> cellIds(nbOfCells);
1220   for(int i=0;i<nbOfCells;i++)
1221     cellIds[i]=i;
1222   convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1223 }
1224
1225 /*!
1226  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1227  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1228  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1229  * base facet of the volume and the second half of nodes describes an opposite facet
1230  * having the same number of nodes as the base one. This method converts such
1231  * connectivity to a valid polyhedral format where connectivity of each facet is
1232  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1233  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1234  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1235  * a correct orientation of the first facet of a polyhedron, else orientation of a
1236  * corrected cell is reverse.<br>
1237  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1238  * it releases the user from boring description of polyhedra connectivity in the valid
1239  * format.
1240  *  \throw If \a this->getMeshDimension() != 3.
1241  *  \throw If \a this->getSpaceDimension() != 3.
1242  *  \throw If the nodal connectivity of cells is not defined.
1243  *  \throw If the coordinates array is not set.
1244  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1245  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1246  *
1247  *  \if ENABLE_EXAMPLES
1248  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1249  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1250  *  \endif
1251  */
1252 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1253 {
1254   checkFullyDefined();
1255   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1256     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1257   int nbOfCells=getNumberOfCells();
1258   MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1259   newCi->alloc(nbOfCells+1,1);
1260   int *newci=newCi->getPointer();
1261   const int *ci=_nodal_connec_index->getConstPointer();
1262   const int *c=_nodal_connec->getConstPointer();
1263   newci[0]=0;
1264   for(int i=0;i<nbOfCells;i++)
1265     {
1266       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1267       if(type==INTERP_KERNEL::NORM_POLYHED)
1268         {
1269           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1270             {
1271               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1272               throw INTERP_KERNEL::Exception(oss.str());
1273             }
1274           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1275           if(n2%2!=0)
1276             {
1277               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 !";
1278               throw INTERP_KERNEL::Exception(oss.str());
1279             }
1280           int n1=(int)(n2/2);
1281           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)
1282         }
1283       else
1284         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1285     }
1286   MCAuto<DataArrayInt> newC=DataArrayInt::New();
1287   newC->alloc(newci[nbOfCells],1);
1288   int *newc=newC->getPointer();
1289   for(int i=0;i<nbOfCells;i++)
1290     {
1291       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1292       if(type==INTERP_KERNEL::NORM_POLYHED)
1293         {
1294           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1295           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1296           *newc++=-1;
1297           for(std::size_t j=0;j<n1;j++)
1298             {
1299               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1300               newc[n1+5*j]=-1;
1301               newc[n1+5*j+1]=c[ci[i]+1+j];
1302               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1303               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1304               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1305             }
1306           newc+=n1*6;
1307         }
1308       else
1309         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1310     }
1311   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1312   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1313 }
1314
1315
1316 /*!
1317  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1318  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1319  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1320  *          to write this mesh to the MED file, its cells must be sorted using
1321  *          sortCellsInMEDFileFrmt().
1322  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1323  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1324  * \return \c true if at least one cell has been converted, \c false else. In the
1325  *         last case the nodal connectivity remains unchanged.
1326  * \throw If the coordinates array is not set.
1327  * \throw If the nodal connectivity of cells is not defined.
1328  * \throw If \a this->getMeshDimension() < 0.
1329  */
1330 bool MEDCouplingUMesh::unPolyze()
1331 {
1332   checkFullyDefined();
1333   int mdim=getMeshDimension();
1334   if(mdim<0)
1335     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1336   if(mdim<=1)
1337     return false;
1338   int nbOfCells=getNumberOfCells();
1339   if(nbOfCells<1)
1340     return false;
1341   int initMeshLgth=getNodalConnectivityArrayLen();
1342   int *conn=_nodal_connec->getPointer();
1343   int *index=_nodal_connec_index->getPointer();
1344   int posOfCurCell=0;
1345   int newPos=0;
1346   int lgthOfCurCell;
1347   bool ret=false;
1348   for(int i=0;i<nbOfCells;i++)
1349     {
1350       lgthOfCurCell=index[i+1]-posOfCurCell;
1351       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1352       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1353       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1354       int newLgth;
1355       if(cm.isDynamic())
1356         {
1357           switch(cm.getDimension())
1358           {
1359             case 2:
1360               {
1361                 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1362                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1363                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1364                 break;
1365               }
1366             case 3:
1367               {
1368                 int nbOfFaces,lgthOfPolyhConn;
1369                 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1370                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1371                 break;
1372               }
1373             case 1:
1374               {
1375                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1376                 break;
1377               }
1378           }
1379           ret=ret || (newType!=type);
1380           conn[newPos]=newType;
1381           newPos+=newLgth+1;
1382           posOfCurCell=index[i+1];
1383           index[i+1]=newPos;
1384         }
1385       else
1386         {
1387           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1388           newPos+=lgthOfCurCell;
1389           posOfCurCell+=lgthOfCurCell;
1390           index[i+1]=newPos;
1391         }
1392     }
1393   if(newPos!=initMeshLgth)
1394     _nodal_connec->reAlloc(newPos);
1395   if(ret)
1396     computeTypes();
1397   return ret;
1398 }
1399
1400 /*!
1401  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1402  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1403  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. 
1404  *
1405  * \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 
1406  *             precision.
1407  */
1408 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1409 {
1410   checkFullyDefined();
1411   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1412     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1413   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1414   coords->recenterForMaxPrecision(eps);
1415   //
1416   int nbOfCells=getNumberOfCells();
1417   const int *conn=_nodal_connec->getConstPointer();
1418   const int *index=_nodal_connec_index->getConstPointer();
1419   MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1420   connINew->alloc(nbOfCells+1,1);
1421   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1422   MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1423   bool changed=false;
1424   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1425     {
1426       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1427         {
1428           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1429           changed=true;
1430         }
1431       else
1432         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1433       *connINewPtr=connNew->getNumberOfTuples();
1434     }
1435   if(changed)
1436     setConnectivity(connNew,connINew,false);
1437 }
1438
1439 /*!
1440  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1441  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1442  * the format of the returned DataArrayInt instance.
1443  * 
1444  * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1445  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1446  */
1447 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1448 {
1449   checkConnectivityFullyDefined();
1450   const int *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1451   int maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1452   std::vector<bool> retS(maxElt,false);
1453   computeNodeIdsAlg(retS);
1454   return DataArrayInt::BuildListOfSwitchedOn(retS);
1455 }
1456
1457 /*!
1458  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1459  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1460  */
1461 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1462 {
1463   int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1464   const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1465   for(int i=0;i<nbOfCells;i++)
1466     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1467       if(conn[j]>=0)
1468         {
1469           if(conn[j]<nbOfNodes)
1470             nodeIdsInUse[conn[j]]=true;
1471           else
1472             {
1473               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1474               throw INTERP_KERNEL::Exception(oss.str());
1475             }
1476         }
1477 }
1478
1479 /*!
1480  * Finds nodes not used in any cell and returns an array giving a new id to every node
1481  * by excluding the unused nodes, for which the array holds -1. The result array is
1482  * a mapping in "Old to New" mode. 
1483  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1484  *  \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1485  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1486  *          if the node is unused or a new id else. The caller is to delete this
1487  *          array using decrRef() as it is no more needed.  
1488  *  \throw If the coordinates array is not set.
1489  *  \throw If the nodal connectivity of cells is not defined.
1490  *  \throw If the nodal connectivity includes an invalid id.
1491  *
1492  *  \if ENABLE_EXAMPLES
1493  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1494  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1495  *  \endif
1496  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1497  */
1498 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1499 {
1500   nbrOfNodesInUse=-1;
1501   int nbOfNodes(getNumberOfNodes());
1502   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1503   ret->alloc(nbOfNodes,1);
1504   int *traducer=ret->getPointer();
1505   std::fill(traducer,traducer+nbOfNodes,-1);
1506   int nbOfCells=getNumberOfCells();
1507   const int *connIndex=_nodal_connec_index->getConstPointer();
1508   const int *conn=_nodal_connec->getConstPointer();
1509   for(int i=0;i<nbOfCells;i++)
1510     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1511       if(conn[j]>=0)
1512         {
1513           if(conn[j]<nbOfNodes)
1514             traducer[conn[j]]=1;
1515           else
1516             {
1517               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1518               throw INTERP_KERNEL::Exception(oss.str());
1519             }
1520         }
1521   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1522   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1523   return ret.retn();
1524 }
1525
1526 /*!
1527  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1528  * For each cell in \b this the number of nodes constituting cell is computed.
1529  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1530  * So for pohyhedrons some nodes can be counted several times in the returned result.
1531  * 
1532  * \return a newly allocated array
1533  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1534  */
1535 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1536 {
1537   checkConnectivityFullyDefined();
1538   int nbOfCells=getNumberOfCells();
1539   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1540   ret->alloc(nbOfCells,1);
1541   int *retPtr=ret->getPointer();
1542   const int *conn=getNodalConnectivity()->getConstPointer();
1543   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1544   for(int i=0;i<nbOfCells;i++,retPtr++)
1545     {
1546       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1547         *retPtr=connI[i+1]-connI[i]-1;
1548       else
1549         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1550     }
1551   return ret.retn();
1552 }
1553
1554 /*!
1555  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1556  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1557  *
1558  * \return DataArrayInt * - new object to be deallocated by the caller.
1559  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1560  */
1561 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1562 {
1563   checkConnectivityFullyDefined();
1564   int nbOfCells=getNumberOfCells();
1565   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1566   ret->alloc(nbOfCells,1);
1567   int *retPtr=ret->getPointer();
1568   const int *conn=getNodalConnectivity()->getConstPointer();
1569   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1570   for(int i=0;i<nbOfCells;i++,retPtr++)
1571     {
1572       std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1573       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1574         *retPtr=(int)s.size();
1575       else
1576         {
1577           s.erase(-1);
1578           *retPtr=(int)s.size();
1579         }
1580     }
1581   return ret.retn();
1582 }
1583
1584 /*!
1585  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1586  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1587  * 
1588  * \return a newly allocated array
1589  */
1590 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1591 {
1592   checkConnectivityFullyDefined();
1593   int nbOfCells=getNumberOfCells();
1594   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1595   ret->alloc(nbOfCells,1);
1596   int *retPtr=ret->getPointer();
1597   const int *conn=getNodalConnectivity()->getConstPointer();
1598   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1599   for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1600     {
1601       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1602       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1603     }
1604   return ret.retn();
1605 }
1606
1607 /*!
1608  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1609  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1610  * array mean that the corresponding old node is no more used. 
1611  *  \return DataArrayInt * - a new instance of DataArrayInt of length \a
1612  *           this->getNumberOfNodes() before call of this method. The caller is to
1613  *           delete this array using decrRef() as it is no more needed. 
1614  *  \throw If the coordinates array is not set.
1615  *  \throw If the nodal connectivity of cells is not defined.
1616  *  \throw If the nodal connectivity includes an invalid id.
1617  *  \sa areAllNodesFetched
1618  *
1619  *  \if ENABLE_EXAMPLES
1620  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1621  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1622  *  \endif
1623  */
1624 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1625 {
1626   return MEDCouplingPointSet::zipCoordsTraducer();
1627 }
1628
1629 /*!
1630  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1631  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1632  */
1633 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1634 {
1635   switch(compType)
1636   {
1637     case 0:
1638       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1639     case 1:
1640       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1641     case 2:
1642       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1643     case 3:
1644       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1645     case 7:
1646       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1647   }
1648   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1649 }
1650
1651 /*!
1652  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1653  */
1654 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1655 {
1656   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1657     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1658   return 0;
1659 }
1660
1661 /*!
1662  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1663  */
1664 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1665 {
1666   int sz=connI[cell1+1]-connI[cell1];
1667   if(sz==connI[cell2+1]-connI[cell2])
1668     {
1669       if(conn[connI[cell1]]==conn[connI[cell2]])
1670         {
1671           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1672           unsigned dim=cm.getDimension();
1673           if(dim!=3)
1674             {
1675               if(dim!=1)
1676                 {
1677                   int sz1=2*(sz-1);
1678                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1679                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1680                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1681                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1682                   return work!=tmp+sz1?1:0;
1683                 }
1684               else
1685                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1686             }
1687           else
1688             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1689         }
1690     }
1691   return 0;
1692 }
1693
1694 /*!
1695  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1696  */
1697 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1698 {
1699   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1700     {
1701       if(conn[connI[cell1]]==conn[connI[cell2]])
1702         {
1703           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1704           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1705           return s1==s2?1:0;
1706         }
1707     }
1708   return 0;
1709 }
1710
1711 /*!
1712  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1713  */
1714 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1715 {
1716   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1717     {
1718       std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1719       std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1720       return s1==s2?1:0;
1721     }
1722   return 0;
1723 }
1724
1725 /*!
1726  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1727  */
1728 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1729 {
1730   int sz=connI[cell1+1]-connI[cell1];
1731   if(sz==connI[cell2+1]-connI[cell2])
1732     {
1733       if(conn[connI[cell1]]==conn[connI[cell2]])
1734         {
1735           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1736           unsigned dim=cm.getDimension();
1737           if(dim!=3)
1738             {
1739               if(dim!=1)
1740                 {
1741                   int sz1=2*(sz-1);
1742                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1743                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1744                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1745                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1746                   if(work!=tmp+sz1)
1747                     return 1;
1748                   else
1749                     {
1750                       std::reverse_iterator<int *> it1((int *)tmp+sz1);
1751                       std::reverse_iterator<int *> it2((int *)tmp);
1752                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1753                         return 2;
1754                       else
1755                         return 0;
1756                     }
1757
1758                   return work!=tmp+sz1?1:0;
1759                 }
1760               else
1761                 {//case of SEG2 and SEG3
1762                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1763                     return 1;
1764                   if(!cm.isQuadratic())
1765                     {
1766                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1767                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1768                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1769                         return 2;
1770                       return 0;
1771                     }
1772                   else
1773                     {
1774                       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])
1775                         return 2;
1776                       return 0;
1777                     }
1778                 }
1779             }
1780           else
1781             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1782         }
1783     }
1784   return 0;
1785 }
1786
1787 /*!
1788  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1789  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1790  * and result remains unchanged.
1791  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1792  * If in 'candidates' pool -1 value is considered as an empty value.
1793  * WARNING this method returns only ONE set of result !
1794  */
1795 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1796 {
1797   if(candidates.size()<1)
1798     return false;
1799   bool ret=false;
1800   std::vector<int>::const_iterator iter=candidates.begin();
1801   int start=(*iter++);
1802   for(;iter!=candidates.end();iter++)
1803     {
1804       int status=AreCellsEqual(conn,connI,start,*iter,compType);
1805       if(status!=0)
1806         {
1807           if(!ret)
1808             {
1809               result->pushBackSilent(start);
1810               ret=true;
1811             }
1812           if(status==1)
1813             result->pushBackSilent(*iter);
1814           else
1815             result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1816         }
1817     }
1818   return ret;
1819 }
1820
1821 /*!
1822  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1823  * by \a compType.
1824  * This method keeps the coordiantes of \a this. This method is time consuming.
1825  *
1826  * \param [in] compType input specifying the technique used to compare cells each other.
1827  *   - 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.
1828  *   - 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)
1829  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1830  *   - 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
1831  * can be used for users not sensitive to orientation of cell
1832  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1833  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1834  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1835  * \return the correspondance array old to new in a newly allocated array.
1836  * 
1837  */
1838 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1839 {
1840   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1841   getReverseNodalConnectivity(revNodal,revNodalI);
1842   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1843 }
1844
1845 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1846                                           DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1847 {
1848   MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1849   int nbOfCells=nodalI->getNumberOfTuples()-1;
1850   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1851   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1852   const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1853   std::vector<bool> isFetched(nbOfCells,false);
1854   if(startCellId==0)
1855     {
1856       for(int i=0;i<nbOfCells;i++)
1857         {
1858           if(!isFetched[i])
1859             {
1860               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1861               std::vector<int> v,v2;
1862               if(connOfNode!=connPtr+connIPtr[i+1])
1863                 {
1864                   const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1865                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1866                   connOfNode++;
1867                 }
1868               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1869                 if(*connOfNode>=0)
1870                   {
1871                     v=v2;
1872                     const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1873                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1874                     v2.resize(std::distance(v2.begin(),it));
1875                   }
1876               if(v2.size()>1)
1877                 {
1878                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1879                     {
1880                       int pos=commonCellsI->back();
1881                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1882                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1883                         isFetched[*it]=true;
1884                     }
1885                 }
1886             }
1887         }
1888     }
1889   else
1890     {
1891       for(int i=startCellId;i<nbOfCells;i++)
1892         {
1893           if(!isFetched[i])
1894             {
1895               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1896               std::vector<int> v,v2;
1897               if(connOfNode!=connPtr+connIPtr[i+1])
1898                 {
1899                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1900                   connOfNode++;
1901                 }
1902               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1903                 if(*connOfNode>=0)
1904                   {
1905                     v=v2;
1906                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1907                     v2.resize(std::distance(v2.begin(),it));
1908                   }
1909               if(v2.size()>1)
1910                 {
1911                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1912                     {
1913                       int pos=commonCellsI->back();
1914                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1915                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1916                         isFetched[*it]=true;
1917                     }
1918                 }
1919             }
1920         }
1921     }
1922   commonCellsArr=commonCells.retn();
1923   commonCellsIArr=commonCellsI.retn();
1924 }
1925
1926 /*!
1927  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1928  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1929  * than \a this->getNumberOfCells() in the returned array means that there is no
1930  * corresponding cell in \a this mesh.
1931  * It is expected that \a this and \a other meshes share the same node coordinates
1932  * array, if it is not so an exception is thrown. 
1933  *  \param [in] other - the mesh to compare with.
1934  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1935  *         valid values [0,1,2], see zipConnectivityTraducer().
1936  *  \param [out] arr - a new instance of DataArrayInt returning correspondence
1937  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1938  *         values. The caller is to delete this array using
1939  *         decrRef() as it is no more needed.
1940  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1941  *         mesh.
1942  *
1943  *  \if ENABLE_EXAMPLES
1944  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1945  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1946  *  \endif
1947  *  \sa checkDeepEquivalOnSameNodesWith()
1948  *  \sa checkGeoEquivalWith()
1949  */
1950 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1951 {
1952   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1953   int nbOfCells=getNumberOfCells();
1954   static const int possibleCompType[]={0,1,2};
1955   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1956     {
1957       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1958       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1959       oss << " !";
1960       throw INTERP_KERNEL::Exception(oss.str());
1961     }
1962   MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1963   arr=o2n->subArray(nbOfCells);
1964   arr->setName(other->getName());
1965   int tmp;
1966   if(other->getNumberOfCells()==0)
1967     return true;
1968   return arr->getMaxValue(tmp)<nbOfCells;
1969 }
1970
1971 /*!
1972  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1973  * This method tries to determine if \b other is fully included in \b this.
1974  * The main difference is that this method is not expected to throw exception.
1975  * This method has two outputs :
1976  *
1977  * \param other other mesh
1978  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1979  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1980  */
1981 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1982 {
1983   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1984   DataArrayInt *commonCells=0,*commonCellsI=0;
1985   int thisNbCells=getNumberOfCells();
1986   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1987   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1988   const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1989   int otherNbCells=other->getNumberOfCells();
1990   MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1991   arr2->alloc(otherNbCells,1);
1992   arr2->fillWithZero();
1993   int *arr2Ptr=arr2->getPointer();
1994   int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1995   for(int i=0;i<nbOfCommon;i++)
1996     {
1997       int start=commonCellsPtr[commonCellsIPtr[i]];
1998       if(start<thisNbCells)
1999         {
2000           for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2001             {
2002               int sig=commonCellsPtr[j]>0?1:-1;
2003               int val=std::abs(commonCellsPtr[j])-1;
2004               if(val>=thisNbCells)
2005                 arr2Ptr[val-thisNbCells]=sig*(start+1);
2006             }
2007         }
2008     }
2009   arr2->setName(other->getName());
2010   if(arr2->presenceOfValue(0))
2011     return false;
2012   arr=arr2.retn();
2013   return true;
2014 }
2015
2016 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2017 {
2018   if(!other)
2019     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2020   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2021   if(!otherC)
2022     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2023   std::vector<const MEDCouplingUMesh *> ms(2);
2024   ms[0]=this;
2025   ms[1]=otherC;
2026   return MergeUMeshesOnSameCoords(ms);
2027 }
2028
2029 /*!
2030  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2031  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2032  * cellIds is not given explicitely but by a range python like.
2033  * 
2034  * \param start
2035  * \param end
2036  * \param step
2037  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
2038  * \return a newly allocated
2039  * 
2040  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2041  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2042  */
2043 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2044 {
2045   if(getMeshDimension()!=-1)
2046     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2047   else
2048     {
2049       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2050       if(newNbOfCells!=1)
2051         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2052       if(start!=0)
2053         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2054       incrRef();
2055       return const_cast<MEDCouplingUMesh *>(this);
2056     }
2057 }
2058
2059 /*!
2060  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2061  * The result mesh shares or not the node coordinates array with \a this mesh depending
2062  * on \a keepCoords parameter.
2063  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2064  *           to write this mesh to the MED file, its cells must be sorted using
2065  *           sortCellsInMEDFileFrmt().
2066  *  \param [in] begin - an array of cell ids to include to the new mesh.
2067  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2068  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2069  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2070  *         by calling zipCoords().
2071  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2072  *         to delete this mesh using decrRef() as it is no more needed. 
2073  *  \throw If the coordinates array is not set.
2074  *  \throw If the nodal connectivity of cells is not defined.
2075  *  \throw If any cell id in the array \a begin is not valid.
2076  *
2077  *  \if ENABLE_EXAMPLES
2078  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2079  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2080  *  \endif
2081  */
2082 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2083 {
2084   if(getMeshDimension()!=-1)
2085     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2086   else
2087     {
2088       if(end-begin!=1)
2089         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2090       if(begin[0]!=0)
2091         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2092       incrRef();
2093       return const_cast<MEDCouplingUMesh *>(this);
2094     }
2095 }
2096
2097 /*!
2098  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2099  *
2100  * 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.
2101  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2102  * The number of cells of \b this will remain the same with this method.
2103  *
2104  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2105  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2106  * \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 ).
2107  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2108  */
2109 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2110 {
2111   checkConnectivityFullyDefined();
2112   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2113   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2114     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2115   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2118       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2119       throw INTERP_KERNEL::Exception(oss.str());
2120     }
2121   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2122   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2123     {
2124       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2125       throw INTERP_KERNEL::Exception(oss.str());
2126     }
2127   int nbOfCells=getNumberOfCells();
2128   bool easyAssign=true;
2129   const int *connI=_nodal_connec_index->getConstPointer();
2130   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2131   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2132     {
2133       if(*it>=0 && *it<nbOfCells)
2134         {
2135           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2136         }
2137       else
2138         {
2139           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2140           throw INTERP_KERNEL::Exception(oss.str());
2141         }
2142     }
2143   if(easyAssign)
2144     {
2145       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2146       computeTypes();
2147     }
2148   else
2149     {
2150       DataArrayInt *arrOut=0,*arrIOut=0;
2151       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2152                                                arrOut,arrIOut);
2153       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2154       setConnectivity(arrOut,arrIOut,true);
2155     }
2156 }
2157
2158 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2159 {
2160   checkConnectivityFullyDefined();
2161   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2162   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2163     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2164   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2165     {
2166       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2167       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2168       throw INTERP_KERNEL::Exception(oss.str());
2169     }
2170   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2171   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2172     {
2173       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2174       throw INTERP_KERNEL::Exception(oss.str());
2175     }
2176   int nbOfCells=getNumberOfCells();
2177   bool easyAssign=true;
2178   const int *connI=_nodal_connec_index->getConstPointer();
2179   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2180   int it=start;
2181   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2182     {
2183       if(it>=0 && it<nbOfCells)
2184         {
2185           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2186         }
2187       else
2188         {
2189           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2190           throw INTERP_KERNEL::Exception(oss.str());
2191         }
2192     }
2193   if(easyAssign)
2194     {
2195       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2196       computeTypes();
2197     }
2198   else
2199     {
2200       DataArrayInt *arrOut=0,*arrIOut=0;
2201       MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2202                                                 arrOut,arrIOut);
2203       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2204       setConnectivity(arrOut,arrIOut,true);
2205     }
2206 }                      
2207
2208 /*!
2209  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2210  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2211  * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2212  * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2213  *
2214  * \param [in] begin input start of array of node ids.
2215  * \param [in] end input end of array of node ids.
2216  * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2217  * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2218  */
2219 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2220 {
2221   MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2222   checkConnectivityFullyDefined();
2223   int tmp=-1;
2224   int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2225   std::vector<bool> fastFinder(sz,false);
2226   for(const int *work=begin;work!=end;work++)
2227     if(*work>=0 && *work<sz)
2228       fastFinder[*work]=true;
2229   int nbOfCells=getNumberOfCells();
2230   const int *conn=getNodalConnectivity()->getConstPointer();
2231   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2232   for(int i=0;i<nbOfCells;i++)
2233     {
2234       int ref=0,nbOfHit=0;
2235       for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2236         if(*work2>=0)
2237           {
2238             ref++;
2239             if(fastFinder[*work2])
2240               nbOfHit++;
2241           }
2242       if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2243         cellIdsKept->pushBackSilent(i);
2244     }
2245   cellIdsKeptArr=cellIdsKept.retn();
2246 }
2247
2248 /*!
2249  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2250  * this->getMeshDimension(), that bound some cells of \a this mesh.
2251  * The cells of lower dimension to include to the result mesh are selected basing on
2252  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2253  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2254  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2255  * created mesh shares the node coordinates array with \a this mesh. 
2256  *  \param [in] begin - the array of node ids.
2257  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2258  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2259  *         array \a begin are added, else cells whose any node is in the
2260  *         array \a begin are added.
2261  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2262  *         to delete this mesh using decrRef() as it is no more needed. 
2263  *  \throw If the coordinates array is not set.
2264  *  \throw If the nodal connectivity of cells is not defined.
2265  *  \throw If any node id in \a begin is not valid.
2266  *
2267  *  \if ENABLE_EXAMPLES
2268  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2269  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2270  *  \endif
2271  */
2272 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2273 {
2274   MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2275   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2276   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2277   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2278   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2279 }
2280
2281 /*!
2282  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2283  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2284  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2285  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2286  *         by calling zipCoords().
2287  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2288  *         to delete this mesh using decrRef() as it is no more needed. 
2289  *  \throw If the coordinates array is not set.
2290  *  \throw If the nodal connectivity of cells is not defined.
2291  *
2292  *  \if ENABLE_EXAMPLES
2293  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2294  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2295  *  \endif
2296  */
2297 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2298 {
2299   DataArrayInt *desc=DataArrayInt::New();
2300   DataArrayInt *descIndx=DataArrayInt::New();
2301   DataArrayInt *revDesc=DataArrayInt::New();
2302   DataArrayInt *revDescIndx=DataArrayInt::New();
2303   //
2304   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2305   revDesc->decrRef();
2306   desc->decrRef();
2307   descIndx->decrRef();
2308   int nbOfCells=meshDM1->getNumberOfCells();
2309   const int *revDescIndxC=revDescIndx->getConstPointer();
2310   std::vector<int> boundaryCells;
2311   for(int i=0;i<nbOfCells;i++)
2312     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2313       boundaryCells.push_back(i);
2314   revDescIndx->decrRef();
2315   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2316   return ret;
2317 }
2318
2319 /*!
2320  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2321  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2322  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown. 
2323  */
2324 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2325 {
2326   checkFullyDefined();
2327   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2328   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2329   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2330   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2331   //
2332   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2333   desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2334   //
2335   MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2336   MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2337   const int *revDescPtr=revDesc->getConstPointer();
2338   const int *revDescIndxPtr=revDescIndx->getConstPointer();
2339   int nbOfCells=getNumberOfCells();
2340   std::vector<bool> ret1(nbOfCells,false);
2341   int sz=0;
2342   for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2343     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2344       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2345   //
2346   DataArrayInt *ret2=DataArrayInt::New();
2347   ret2->alloc(sz,1);
2348   int *ret2Ptr=ret2->getPointer();
2349   sz=0;
2350   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2351     if(*it)
2352       *ret2Ptr++=sz;
2353   ret2->setName("BoundaryCells");
2354   return ret2;
2355 }
2356
2357 /*!
2358  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2359  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2360  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2361  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2362  *
2363  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2364  * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2365  * equals a cell in \b otherDimM1OnSameCoords.
2366  *
2367  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2368  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2369  *
2370  * \param [in] otherDimM1OnSameCoords
2371  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2372  * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2373  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2374  */
2375 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2376 {
2377   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2378     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2379   checkConnectivityFullyDefined();
2380   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2381   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2382     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2383   MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2384   MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2385   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2386   MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2387   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2388   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2389   DataArrayInt *idsOtherInConsti=0;
2390   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2391   MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2392   if(!b)
2393     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2394   std::set<int> s1;
2395   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2396     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2397   MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2398   s1arr_renum1->sort();
2399   cellIdsRk0=s0arr.retn();
2400   //cellIdsRk1=s_renum1.retn();
2401   cellIdsRk1=s1arr_renum1.retn();
2402 }
2403
2404 /*!
2405  * 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
2406  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2407  * 
2408  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2409  */
2410 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2411 {
2412   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2413   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2414   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2415   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2416   //
2417   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2418   revDesc=0; desc=0; descIndx=0;
2419   MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2420   MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2421   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2422 }
2423
2424 /*!
2425  * Finds nodes lying on the boundary of \a this mesh.
2426  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2427  *          nodes. The caller is to delete this array using decrRef() as it is no
2428  *          more needed.
2429  *  \throw If the coordinates array is not set.
2430  *  \throw If the nodal connectivity of cells is node defined.
2431  *
2432  *  \if ENABLE_EXAMPLES
2433  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2434  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2435  *  \endif
2436  */
2437 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2438 {
2439   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2440   return skin->computeFetchedNodeIds();
2441 }
2442
2443 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2444 {
2445   incrRef();
2446   return const_cast<MEDCouplingUMesh *>(this);
2447 }
2448
2449 /*!
2450  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2451  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2452  * 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.
2453  * 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.
2454  * 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.
2455  *
2456  * \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
2457  *             parameter is altered during the call.
2458  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2459  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2460  * \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.
2461  *
2462  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2463  */
2464 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2465                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2466 {
2467   typedef MCAuto<DataArrayInt> DAInt;
2468   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2469
2470   checkFullyDefined();
2471   otherDimM1OnSameCoords.checkFullyDefined();
2472   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2474   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2475     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2476
2477   // Checking star-shaped M1 group:
2478   DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2479   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2480   DAInt dsi = rdit0->deltaShiftIndex();
2481   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2482   if(idsTmp0->getNumberOfTuples())
2483     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2484   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2485
2486   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2487   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2488   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2489   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2490   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2491   dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2492   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2493   dsi = rdit0->deltaShiftIndex();
2494   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2495   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2496   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2497   // In 3D, some points on the boundary of M0 still need duplication:
2498   DAInt notDup = 0;
2499   if (getMeshDimension() == 3)
2500     {
2501       DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2502       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2503       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2504       DataArrayInt * corresp=0;
2505       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2506       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2507       corresp->decrRef();
2508       if (validIds->getNumberOfTuples())
2509         {
2510           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2511           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2512           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2513           notDup = xtrem->buildSubstraction(fNodes1);
2514         }
2515       else
2516         notDup = xtrem->buildSubstraction(fNodes);
2517     }
2518   else
2519     notDup = xtrem->buildSubstraction(fNodes);
2520
2521   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2522   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2523   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2524   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2525
2526   //
2527   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2528   int nCells2 = m0Part2->getNumberOfCells();
2529   DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2530   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2531
2532   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2533   DataArrayInt *tmp00=0,*tmp11=0;
2534   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2535   DAInt neighInit00(tmp00);
2536   DAInt neighIInit00(tmp11);
2537   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2538   DataArrayInt *idsTmp=0;
2539   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2540   DAInt ids(idsTmp);
2541   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2542   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2543   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2544   DataArrayInt *tmp0=0,*tmp1=0;
2545   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2546   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2547   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2548   DAInt neigh00(tmp0);
2549   DAInt neighI00(tmp1);
2550
2551   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2552   int seed = 0, nIter = 0;
2553   int nIterMax = nCells2+1; // Safety net for the loop
2554   DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2555   hitCells->fillWithValue(-1);
2556   DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2557   cellsToModifyConn0_torenum->alloc(0,1);
2558   while (nIter < nIterMax)
2559     {
2560       DAInt t = hitCells->findIdsEqual(-1);
2561       if (!t->getNumberOfTuples())
2562         break;
2563       // Connex zone without the crack (to compute the next seed really)
2564       int dnu;
2565       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2566       int cnt = 0;
2567       for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2568         hitCells->setIJ(*ptr,0,1);
2569       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2570       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2571       cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2572       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2573       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2574       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2575       DAInt intersec = nonHitCells->buildIntersection(comple);
2576       if (intersec->getNumberOfTuples())
2577         { seed = intersec->getIJ(0,0); }
2578       else
2579         { break; }
2580       nIter++;
2581     }
2582   if (nIter >= nIterMax)
2583     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2584
2585   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2586   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2587   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2588   //
2589   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2590   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2591   nodeIdsToDuplicate=dupl.retn();
2592 }
2593
2594 /*!
2595  * This method operates a modification of the connectivity and coords in \b this.
2596  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2597  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2598  * 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
2599  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2600  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2601  * 
2602  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2603  * 
2604  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2605  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2606  */
2607 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2608 {
2609   int nbOfNodes=getNumberOfNodes();
2610   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2611   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2612 }
2613
2614 /*!
2615  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2616  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2617  *
2618  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2619  *
2620  * \sa renumberNodesInConn
2621  */
2622 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2623 {
2624   checkConnectivityFullyDefined();
2625   int *conn(getNodalConnectivity()->getPointer());
2626   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2627   int nbOfCells(getNumberOfCells());
2628   for(int i=0;i<nbOfCells;i++)
2629     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2630       {
2631         int& node=conn[iconn];
2632         if(node>=0)//avoid polyhedron separator
2633           {
2634             node+=offset;
2635           }
2636       }
2637   _nodal_connec->declareAsNew();
2638   updateTime();
2639 }
2640
2641 /*!
2642  *  Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2643  *  of array. This method is dedicated for renumbering from a big set of nodes the a tiny set of nodes which is the case during extraction
2644  *  of a big mesh.
2645  */
2646 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2647 {
2648   checkConnectivityFullyDefined();
2649   int *conn(getNodalConnectivity()->getPointer());
2650   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2651   int nbOfCells(getNumberOfCells());
2652   for(int i=0;i<nbOfCells;i++)
2653     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2654       {
2655         int& node=conn[iconn];
2656         if(node>=0)//avoid polyhedron separator
2657           {
2658             INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2659             if(it!=newNodeNumbersO2N.end())
2660               {
2661                 node=(*it).second;
2662               }
2663             else
2664               {
2665                 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2666                 throw INTERP_KERNEL::Exception(oss.str());
2667               }
2668           }
2669       }
2670   _nodal_connec->declareAsNew();
2671   updateTime();
2672 }
2673
2674 /*!
2675  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2676  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2677  * This method is a generalization of shiftNodeNumbersInConn().
2678  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2679  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2680  *         this->getNumberOfNodes(), in "Old to New" mode. 
2681  *         See \ref numbering for more info on renumbering modes.
2682  *  \throw If the nodal connectivity of cells is not defined.
2683  *
2684  *  \if ENABLE_EXAMPLES
2685  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2686  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2687  *  \endif
2688  */
2689 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2690 {
2691   checkConnectivityFullyDefined();
2692   int *conn=getNodalConnectivity()->getPointer();
2693   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2694   int nbOfCells(getNumberOfCells());
2695   for(int i=0;i<nbOfCells;i++)
2696     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2697       {
2698         int& node=conn[iconn];
2699         if(node>=0)//avoid polyhedron separator
2700           {
2701             node=newNodeNumbersO2N[node];
2702           }
2703       }
2704   _nodal_connec->declareAsNew();
2705   updateTime();
2706 }
2707
2708 /*!
2709  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2710  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2711  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2712  * 
2713  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2714  */
2715 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2716 {
2717   checkConnectivityFullyDefined();
2718   int *conn=getNodalConnectivity()->getPointer();
2719   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2720   int nbOfCells=getNumberOfCells();
2721   for(int i=0;i<nbOfCells;i++)
2722     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2723       {
2724         int& node=conn[iconn];
2725         if(node>=0)//avoid polyhedron separator
2726           {
2727             node+=delta;
2728           }
2729       }
2730   _nodal_connec->declareAsNew();
2731   updateTime();
2732 }
2733
2734 /*!
2735  * This method operates a modification of the connectivity in \b this.
2736  * 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.
2737  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2738  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2739  * 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
2740  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2741  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2742  * 
2743  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2744  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2745  * 
2746  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2747  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2748  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ). 
2749  */
2750 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2751 {
2752   checkConnectivityFullyDefined();
2753   std::map<int,int> m;
2754   int val=offset;
2755   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2756     m[*work]=val;
2757   int *conn=getNodalConnectivity()->getPointer();
2758   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2759   int nbOfCells=getNumberOfCells();
2760   for(int i=0;i<nbOfCells;i++)
2761     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2762       {
2763         int& node=conn[iconn];
2764         if(node>=0)//avoid polyhedron separator
2765           {
2766             std::map<int,int>::iterator it=m.find(node);
2767             if(it!=m.end())
2768               node=(*it).second;
2769           }
2770       }
2771   updateTime();
2772 }
2773
2774 /*!
2775  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2776  *
2777  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2778  * After the call of this method the number of cells remains the same as before.
2779  *
2780  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2781  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2782  * be strictly in [0;this->getNumberOfCells()).
2783  *
2784  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2785  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2786  * should be contained in[0;this->getNumberOfCells()).
2787  * 
2788  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2789  * \param check
2790  */
2791 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2792 {
2793   checkConnectivityFullyDefined();
2794   int nbCells=getNumberOfCells();
2795   const int *array=old2NewBg;
2796   if(check)
2797     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2798   //
2799   const int *conn=_nodal_connec->getConstPointer();
2800   const int *connI=_nodal_connec_index->getConstPointer();
2801   MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2802   MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2803   const int *n2oPtr=n2o->begin();
2804   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2805   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2806   newConn->copyStringInfoFrom(*_nodal_connec);
2807   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2808   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2809   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2810   //
2811   int *newC=newConn->getPointer();
2812   int *newCI=newConnI->getPointer();
2813   int loc=0;
2814   newCI[0]=loc;
2815   for(int i=0;i<nbCells;i++)
2816     {
2817       int pos=n2oPtr[i];
2818       int nbOfElts=connI[pos+1]-connI[pos];
2819       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2820       loc+=nbOfElts;
2821       newCI[i+1]=loc;
2822     }
2823   //
2824   setConnectivity(newConn,newConnI);
2825   if(check)
2826     free(const_cast<int *>(array));
2827 }
2828
2829 /*!
2830  * Finds cells whose bounding boxes intersect a given bounding box.
2831  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2832  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2833  *         zMax (if in 3D). 
2834  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2835  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2836  *         extent of the bounding box of cell to produce an addition to this bounding box.
2837  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2838  *         cells. The caller is to delete this array using decrRef() as it is no more
2839  *         needed. 
2840  *  \throw If the coordinates array is not set.
2841  *  \throw If the nodal connectivity of cells is not defined.
2842  *
2843  *  \if ENABLE_EXAMPLES
2844  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2845  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2846  *  \endif
2847  */
2848 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2849 {
2850   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2851   if(getMeshDimension()==-1)
2852     {
2853       elems->pushBackSilent(0);
2854       return elems.retn();
2855     }
2856   int dim=getSpaceDimension();
2857   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2858   const int* conn      = getNodalConnectivity()->getConstPointer();
2859   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2860   const double* coords = getCoords()->getConstPointer();
2861   int nbOfCells=getNumberOfCells();
2862   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2863     {
2864       for (int i=0; i<dim; i++)
2865         {
2866           elem_bb[i*2]=std::numeric_limits<double>::max();
2867           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2868         }
2869
2870       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2871         {
2872           int node= conn[inode];
2873           if(node>=0)//avoid polyhedron separator
2874             {
2875               for (int idim=0; idim<dim; idim++)
2876                 {
2877                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2878                     {
2879                       elem_bb[idim*2] = coords[node*dim+idim] ;
2880                     }
2881                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2882                     {
2883                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2884                     }
2885                 }
2886             }
2887         }
2888       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2889         elems->pushBackSilent(ielem);
2890     }
2891   return elems.retn();
2892 }
2893
2894 /*!
2895  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2896  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2897  * added in 'elems' parameter.
2898  */
2899 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2900 {
2901   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2902   if(getMeshDimension()==-1)
2903     {
2904       elems->pushBackSilent(0);
2905       return elems.retn();
2906     }
2907   int dim=getSpaceDimension();
2908   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2909   const int* conn      = getNodalConnectivity()->getConstPointer();
2910   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2911   const double* coords = getCoords()->getConstPointer();
2912   int nbOfCells=getNumberOfCells();
2913   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2914     {
2915       for (int i=0; i<dim; i++)
2916         {
2917           elem_bb[i*2]=std::numeric_limits<double>::max();
2918           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2919         }
2920
2921       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2922         {
2923           int node= conn[inode];
2924           if(node>=0)//avoid polyhedron separator
2925             {
2926               for (int idim=0; idim<dim; idim++)
2927                 {
2928                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2929                     {
2930                       elem_bb[idim*2] = coords[node*dim+idim] ;
2931                     }
2932                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2933                     {
2934                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2935                     }
2936                 }
2937             }
2938         }
2939       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2940         elems->pushBackSilent(ielem);
2941     }
2942   return elems.retn();
2943 }
2944
2945 /*!
2946  * Returns a type of a cell by its id.
2947  *  \param [in] cellId - the id of the cell of interest.
2948  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2949  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2950  */
2951 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2952 {
2953   const int *ptI=_nodal_connec_index->getConstPointer();
2954   const int *pt=_nodal_connec->getConstPointer();
2955   if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2956     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2957   else
2958     {
2959       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2960       throw INTERP_KERNEL::Exception(oss.str());
2961     }
2962 }
2963
2964 /*!
2965  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2966  * This method does not throw exception if geometric type \a type is not in \a this.
2967  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2968  * The coordinates array is not considered here.
2969  *
2970  * \param [in] type the geometric type
2971  * \return cell ids in this having geometric type \a type.
2972  */
2973 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2974 {
2975
2976   MCAuto<DataArrayInt> ret=DataArrayInt::New();
2977   ret->alloc(0,1);
2978   checkConnectivityFullyDefined();
2979   int nbCells=getNumberOfCells();
2980   int mdim=getMeshDimension();
2981   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2982   if(mdim!=(int)cm.getDimension())
2983     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2984   const int *ptI=_nodal_connec_index->getConstPointer();
2985   const int *pt=_nodal_connec->getConstPointer();
2986   for(int i=0;i<nbCells;i++)
2987     {
2988       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2989         ret->pushBackSilent(i);
2990     }
2991   return ret.retn();
2992 }
2993
2994 /*!
2995  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2996  */
2997 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2998 {
2999   const int *ptI=_nodal_connec_index->getConstPointer();
3000   const int *pt=_nodal_connec->getConstPointer();
3001   int nbOfCells=getNumberOfCells();
3002   int ret=0;
3003   for(int i=0;i<nbOfCells;i++)
3004     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3005       ret++;
3006   return ret;
3007 }
3008
3009 /*!
3010  * Returns the nodal connectivity of a given cell.
3011  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3012  * all returned node ids can be used in getCoordinatesOfNode().
3013  *  \param [in] cellId - an id of the cell of interest.
3014  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3015  *         cleared before the appending.
3016  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3017  */
3018 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
3019 {
3020   const int *ptI=_nodal_connec_index->getConstPointer();
3021   const int *pt=_nodal_connec->getConstPointer();
3022   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3023     if(*w>=0)
3024       conn.push_back(*w);
3025 }
3026
3027 std::string MEDCouplingUMesh::simpleRepr() const
3028 {
3029   static const char msg0[]="No coordinates specified !";
3030   std::ostringstream ret;
3031   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3032   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3033   int tmpp1,tmpp2;
3034   double tt=getTime(tmpp1,tmpp2);
3035   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3036   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3037   if(_mesh_dim>=-1)
3038     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3039   else
3040     { ret << " Mesh dimension has not been set or is invalid !"; }
3041   if(_coords!=0)
3042     {
3043       const int spaceDim=getSpaceDimension();
3044       ret << spaceDim << "\nInfo attached on space dimension : ";
3045       for(int i=0;i<spaceDim;i++)
3046         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3047       ret << "\n";
3048     }
3049   else
3050     ret << msg0 << "\n";
3051   ret << "Number of nodes : ";
3052   if(_coords!=0)
3053     ret << getNumberOfNodes() << "\n";
3054   else
3055     ret << msg0 << "\n";
3056   ret << "Number of cells : ";
3057   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3058     ret << getNumberOfCells() << "\n";
3059   else
3060     ret << "No connectivity specified !" << "\n";
3061   ret << "Cell types present : ";
3062   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3063     {
3064       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3065       ret << cm.getRepr() << " ";
3066     }
3067   ret << "\n";
3068   return ret.str();
3069 }
3070
3071 std::string MEDCouplingUMesh::advancedRepr() const
3072 {
3073   std::ostringstream ret;
3074   ret << simpleRepr();
3075   ret << "\nCoordinates array : \n___________________\n\n";
3076   if(_coords)
3077     _coords->reprWithoutNameStream(ret);
3078   else
3079     ret << "No array set !\n";
3080   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3081   reprConnectivityOfThisLL(ret);
3082   return ret.str();
3083 }
3084
3085 /*!
3086  * This method returns a C++ code that is a dump of \a this.
3087  * This method will throw if this is not fully defined.
3088  */
3089 std::string MEDCouplingUMesh::cppRepr() const
3090 {
3091   static const char coordsName[]="coords";
3092   static const char connName[]="conn";
3093   static const char connIName[]="connI";
3094   checkFullyDefined();
3095   std::ostringstream ret; ret << "// coordinates" << std::endl;
3096   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3097   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3098   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3099   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3100   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3101   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3102   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3103   return ret.str();
3104 }
3105
3106 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3107 {
3108   std::ostringstream ret;
3109   reprConnectivityOfThisLL(ret);
3110   return ret.str();
3111 }
3112
3113 /*!
3114  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3115  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3116  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3117  * some algos).
3118  * 
3119  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3120  * This method analyzes the 3 arrays of \a this. For each the following behaviour is done : if the array is null a newly one is created
3121  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3122  */
3123 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3124 {
3125   int mdim=getMeshDimension();
3126   if(mdim<0)
3127     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3128   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3129   MCAuto<DataArrayInt> tmp1,tmp2;
3130   bool needToCpyCT=true;
3131   if(!_nodal_connec)
3132     {
3133       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3134       needToCpyCT=false;
3135     }
3136   else
3137     {
3138       tmp1=_nodal_connec;
3139       tmp1->incrRef();
3140     }
3141   if(!_nodal_connec_index)
3142     {
3143       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3144       needToCpyCT=false;
3145     }
3146   else
3147     {
3148       tmp2=_nodal_connec_index;
3149       tmp2->incrRef();
3150     }
3151   ret->setConnectivity(tmp1,tmp2,false);
3152   if(needToCpyCT)
3153     ret->_types=_types;
3154   if(!_coords)
3155     {
3156       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3157       ret->setCoords(coords);
3158     }
3159   else
3160     ret->setCoords(_coords);
3161   return ret.retn();
3162 }
3163
3164 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3165 {
3166   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3167     {
3168       int nbOfCells=getNumberOfCells();
3169       const int *c=_nodal_connec->getConstPointer();
3170       const int *ci=_nodal_connec_index->getConstPointer();
3171       for(int i=0;i<nbOfCells;i++)
3172         {
3173           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3174           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3175           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3176           stream << "\n";
3177         }
3178     }
3179   else
3180     stream << "Connectivity not defined !\n";
3181 }
3182
3183 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3184 {
3185   const int *ptI=_nodal_connec_index->getConstPointer();
3186   const int *pt=_nodal_connec->getConstPointer();
3187   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3188     return ptI[cellId+1]-ptI[cellId]-1;
3189   else
3190     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3191 }
3192
3193 /*!
3194  * Returns types of cells of the specified part of \a this mesh.
3195  * This method avoids computing sub-mesh explicitely to get its types.
3196  *  \param [in] begin - an array of cell ids of interest.
3197  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3198  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3199  *         describing the cell types. 
3200  *  \throw If the coordinates array is not set.
3201  *  \throw If the nodal connectivity of cells is not defined.
3202  *  \sa getAllGeoTypes()
3203  */
3204 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3205 {
3206   checkFullyDefined();
3207   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3208   const int *conn=_nodal_connec->getConstPointer();
3209   const int *connIndex=_nodal_connec_index->getConstPointer();
3210   for(const int *w=begin;w!=end;w++)
3211     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3212   return ret;
3213 }
3214
3215 /*!
3216  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3217  * Optionally updates
3218  * a set of types of cells constituting \a this mesh. 
3219  * This method is for advanced users having prepared their connectivity before. For
3220  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3221  *  \param [in] conn - the nodal connectivity array. 
3222  *  \param [in] connIndex - the nodal connectivity index array.
3223  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3224  *         mesh is updated.
3225  */
3226 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3227 {
3228   DataArrayInt::SetArrayIn(conn,_nodal_connec);
3229   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3230   if(isComputingTypes)
3231     computeTypes();
3232   declareAsNew();
3233 }
3234
3235 /*!
3236  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3237  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3238  */
3239 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3240     _nodal_connec(0),_nodal_connec_index(0),
3241     _types(other._types)
3242 {
3243   if(other._nodal_connec)
3244     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3245   if(other._nodal_connec_index)
3246     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3247 }
3248
3249 MEDCouplingUMesh::~MEDCouplingUMesh()
3250 {
3251   if(_nodal_connec)
3252     _nodal_connec->decrRef();
3253   if(_nodal_connec_index)
3254     _nodal_connec_index->decrRef();
3255 }
3256
3257 /*!
3258  * Recomputes a set of cell types of \a this mesh. For more info see
3259  * \ref MEDCouplingUMeshNodalConnectivity.
3260  */
3261 void MEDCouplingUMesh::computeTypes()
3262 {
3263   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3264 }
3265
3266 /*!
3267  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3268  */
3269 void MEDCouplingUMesh::checkFullyDefined() const
3270 {
3271   if(!_nodal_connec_index || !_nodal_connec || !_coords)
3272     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3273 }
3274
3275 /*!
3276  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3277  */
3278 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3279 {
3280   if(!_nodal_connec_index || !_nodal_connec)
3281     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3282 }
3283
3284 /*!
3285  * Returns a number of cells constituting \a this mesh. 
3286  *  \return int - the number of cells in \a this mesh.
3287  *  \throw If the nodal connectivity of cells is not defined.
3288  */
3289 int MEDCouplingUMesh::getNumberOfCells() const
3290
3291   if(_nodal_connec_index)
3292     return _nodal_connec_index->getNumberOfTuples()-1;
3293   else
3294     if(_mesh_dim==-1)
3295       return 1;
3296     else
3297       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3298 }
3299
3300 /*!
3301  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3302  * mesh. For more info see \ref meshes.
3303  *  \return int - the dimension of \a this mesh.
3304  *  \throw If the mesh dimension is not defined using setMeshDimension().
3305  */
3306 int MEDCouplingUMesh::getMeshDimension() const
3307 {
3308   if(_mesh_dim<-1)
3309     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3310   return _mesh_dim;
3311 }
3312
3313 /*!
3314  * Returns a length of the nodal connectivity array.
3315  * This method is for test reason. Normally the integer returned is not useable by
3316  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3317  *  \return int - the length of the nodal connectivity array.
3318  */
3319 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3320 {
3321   return _nodal_connec->getNbOfElems();
3322 }
3323
3324 /*!
3325  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3326  */
3327 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3328 {
3329   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3330   tinyInfo.push_back(getMeshDimension());
3331   tinyInfo.push_back(getNumberOfCells());
3332   if(_nodal_connec)
3333     tinyInfo.push_back(getNodalConnectivityArrayLen());
3334   else
3335     tinyInfo.push_back(-1);
3336 }
3337
3338 /*!
3339  * First step of unserialization process.
3340  */
3341 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3342 {
3343   return tinyInfo[6]<=0;
3344 }
3345
3346 /*!
3347  * Second step of serialization process.
3348  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3349  * \param a1
3350  * \param a2
3351  * \param littleStrings
3352  */
3353 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3354 {
3355   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3356   if(tinyInfo[5]!=-1)
3357     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3358 }
3359
3360 /*!
3361  * Third and final step of serialization process.
3362  */
3363 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3364 {
3365   MEDCouplingPointSet::serialize(a1,a2);
3366   if(getMeshDimension()>-1)
3367     {
3368       a1=DataArrayInt::New();
3369       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3370       int *ptA1=a1->getPointer();
3371       const int *conn=getNodalConnectivity()->getConstPointer();
3372       const int *index=getNodalConnectivityIndex()->getConstPointer();
3373       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3374       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3375     }
3376   else
3377     a1=0;
3378 }
3379
3380 /*!
3381  * Second and final unserialization process.
3382  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3383  */
3384 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3385 {
3386   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3387   setMeshDimension(tinyInfo[5]);
3388   if(tinyInfo[7]!=-1)
3389     {
3390       // Connectivity
3391       const int *recvBuffer=a1->getConstPointer();
3392       MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3393       myConnecIndex->alloc(tinyInfo[6]+1,1);
3394       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3395       MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3396       myConnec->alloc(tinyInfo[7],1);
3397       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3398       setConnectivity(myConnec, myConnecIndex);
3399     }
3400 }
3401
3402 /*!
3403  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3404  * CellIds are given using range specified by a start an end and step.
3405  */
3406 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3407 {
3408   checkFullyDefined();
3409   int ncell=getNumberOfCells();
3410   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3411   ret->_mesh_dim=_mesh_dim;
3412   ret->setCoords(_coords);
3413   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3414   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3415   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3416   int work=start;
3417   const int *conn=_nodal_connec->getConstPointer();
3418   const int *connIndex=_nodal_connec_index->getConstPointer();
3419   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3420     {
3421       if(work>=0 && work<ncell)
3422         {
3423           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3424         }
3425       else
3426         {
3427           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3428           throw INTERP_KERNEL::Exception(oss.str());
3429         }
3430     }
3431   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3432   int *newConnPtr=newConn->getPointer();
3433   std::set<INTERP_KERNEL::NormalizedCellType> types;
3434   work=start;
3435   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3436     {
3437       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3438       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3439     }
3440   ret->setConnectivity(newConn,newConnI,false);
3441   ret->_types=types;
3442   ret->copyTinyInfoFrom(this);
3443   return ret.retn();
3444 }
3445
3446 /*!
3447  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3448  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3449  * The return newly allocated mesh will share the same coordinates as \a this.
3450  */
3451 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3452 {
3453   checkConnectivityFullyDefined();
3454   int ncell=getNumberOfCells();
3455   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3456   ret->_mesh_dim=_mesh_dim;
3457   ret->setCoords(_coords);
3458   std::size_t nbOfElemsRet=std::distance(begin,end);
3459   int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3460   connIndexRet[0]=0;
3461   const int *conn=_nodal_connec->getConstPointer();
3462   const int *connIndex=_nodal_connec_index->getConstPointer();
3463   int newNbring=0;
3464   for(const int *work=begin;work!=end;work++,newNbring++)
3465     {
3466       if(*work>=0 && *work<ncell)
3467         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3468       else
3469         {
3470           free(connIndexRet);
3471           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3472           throw INTERP_KERNEL::Exception(oss.str());
3473         }
3474     }
3475   int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3476   int *connRetWork=connRet;
3477   std::set<INTERP_KERNEL::NormalizedCellType> types;
3478   for(const int *work=begin;work!=end;work++)
3479     {
3480       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3481       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3482     }
3483   MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3484   connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3485   MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3486   connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3487   ret->setConnectivity(connRetArr,connIndexRetArr,false);
3488   ret->_types=types;
3489   ret->copyTinyInfoFrom(this);
3490   return ret.retn();
3491 }
3492
3493 /*!
3494  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3495  * mesh.<br>
3496  * For 1D cells, the returned field contains lengths.<br>
3497  * For 2D cells, the returned field contains areas.<br>
3498  * For 3D cells, the returned field contains volumes.
3499  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3500  *         orientation, i.e. the volume is always positive.
3501  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3502  *         and one time . The caller is to delete this field using decrRef() as it is no
3503  *         more needed.
3504  */
3505 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3506 {
3507   std::string name="MeasureOfMesh_";
3508   name+=getName();
3509   int nbelem=getNumberOfCells();
3510   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3511   field->setName(name);
3512   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3513   array->alloc(nbelem,1);
3514   double *area_vol=array->getPointer();
3515   field->setArray(array) ; array=0;
3516   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3517   field->synchronizeTimeWithMesh();
3518   if(getMeshDimension()!=-1)
3519     {
3520       int ipt;
3521       INTERP_KERNEL::NormalizedCellType type;
3522       int dim_space=getSpaceDimension();
3523       const double *coords=getCoords()->getConstPointer();
3524       const int *connec=getNodalConnectivity()->getConstPointer();
3525       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3526       for(int iel=0;iel<nbelem;iel++)
3527         {
3528           ipt=connec_index[iel];
3529           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3530           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);
3531         }
3532       if(isAbs)
3533         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3534     }
3535   else
3536     {
3537       area_vol[0]=std::numeric_limits<double>::max();
3538     }
3539   return field.retn();
3540 }
3541
3542 /*!
3543  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3544  * mesh.<br>
3545  * For 1D cells, the returned array contains lengths.<br>
3546  * For 2D cells, the returned array contains areas.<br>
3547  * For 3D cells, the returned array contains volumes.
3548  * This method avoids building explicitly a part of \a this mesh to perform the work.
3549  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3550  *         orientation, i.e. the volume is always positive.
3551  *  \param [in] begin - an array of cell ids of interest.
3552  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3553  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3554  *          delete this array using decrRef() as it is no more needed.
3555  * 
3556  *  \if ENABLE_EXAMPLES
3557  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3558  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3559  *  \endif
3560  *  \sa getMeasureField()
3561  */
3562 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3563 {
3564   std::string name="PartMeasureOfMesh_";
3565   name+=getName();
3566   int nbelem=(int)std::distance(begin,end);
3567   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3568   array->setName(name);
3569   array->alloc(nbelem,1);
3570   double *area_vol=array->getPointer();
3571   if(getMeshDimension()!=-1)
3572     {
3573       int ipt;
3574       INTERP_KERNEL::NormalizedCellType type;
3575       int dim_space=getSpaceDimension();
3576       const double *coords=getCoords()->getConstPointer();
3577       const int *connec=getNodalConnectivity()->getConstPointer();
3578       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3579       for(const int *iel=begin;iel!=end;iel++)
3580         {
3581           ipt=connec_index[*iel];
3582           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3583           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3584         }
3585       if(isAbs)
3586         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3587     }
3588   else
3589     {
3590       area_vol[0]=std::numeric_limits<double>::max();
3591     }
3592   return array.retn();
3593 }
3594
3595 /*!
3596  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3597  * \a this one. The returned field contains the dual cell volume for each corresponding
3598  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3599  *  the dual mesh in P1 sens of \a this.<br>
3600  * For 1D cells, the returned field contains lengths.<br>
3601  * For 2D cells, the returned field contains areas.<br>
3602  * For 3D cells, the returned field contains volumes.
3603  * This method is useful to check "P1*" conservative interpolators.
3604  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3605  *         orientation, i.e. the volume is always positive.
3606  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3607  *          nodes and one time. The caller is to delete this array using decrRef() as
3608  *          it is no more needed.
3609  */
3610 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3611 {
3612   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3613   std::string name="MeasureOnNodeOfMesh_";
3614   name+=getName();
3615   int nbNodes=getNumberOfNodes();
3616   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3617   double cst=1./((double)getMeshDimension()+1.);
3618   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3619   array->alloc(nbNodes,1);
3620   double *valsToFill=array->getPointer();
3621   std::fill(valsToFill,valsToFill+nbNodes,0.);
3622   const double *values=tmp->getArray()->getConstPointer();
3623   MCAuto<DataArrayInt> da=DataArrayInt::New();
3624   MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3625   getReverseNodalConnectivity(da,daInd);
3626   const int *daPtr=da->getConstPointer();
3627   const int *daIPtr=daInd->getConstPointer();
3628   for(int i=0;i<nbNodes;i++)
3629     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3630       valsToFill[i]+=cst*values[*cell];
3631   ret->setMesh(this);
3632   ret->setArray(array);
3633   return ret.retn();
3634 }
3635
3636 /*!
3637  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3638  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3639  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3640  * and are normalized.
3641  * <br> \a this can be either 
3642  * - a  2D mesh in 2D or 3D space or 
3643  * - an 1D mesh in 2D space.
3644  * 
3645  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3646  *          cells and one time. The caller is to delete this field using decrRef() as
3647  *          it is no more needed.
3648  *  \throw If the nodal connectivity of cells is not defined.
3649  *  \throw If the coordinates array is not set.
3650  *  \throw If the mesh dimension is not set.
3651  *  \throw If the mesh and space dimension is not as specified above.
3652  */
3653 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3654 {
3655   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3656     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3657   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3658   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3659   int nbOfCells=getNumberOfCells();
3660   int nbComp=getMeshDimension()+1;
3661   array->alloc(nbOfCells,nbComp);
3662   double *vals=array->getPointer();
3663   const int *connI=_nodal_connec_index->getConstPointer();
3664   const int *conn=_nodal_connec->getConstPointer();
3665   const double *coords=_coords->getConstPointer();
3666   if(getMeshDimension()==2)
3667     {
3668       if(getSpaceDimension()==3)
3669         {
3670           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3671           const double *locPtr=loc->getConstPointer();
3672           for(int i=0;i<nbOfCells;i++,vals+=3)
3673             {
3674               int offset=connI[i];
3675               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3676               double n=INTERP_KERNEL::norm<3>(vals);
3677               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3678             }
3679         }
3680       else
3681         {
3682           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3683           const double *isAbsPtr=isAbs->getArray()->begin();
3684           for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3685             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3686         }
3687     }
3688   else//meshdimension==1
3689     {
3690       double tmp[2];
3691       for(int i=0;i<nbOfCells;i++)
3692         {
3693           int offset=connI[i];
3694           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3695           double n=INTERP_KERNEL::norm<2>(tmp);
3696           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3697           *vals++=-tmp[1];
3698           *vals++=tmp[0];
3699         }
3700     }
3701   ret->setArray(array);
3702   ret->setMesh(this);
3703   ret->synchronizeTimeWithSupport();
3704   return ret.retn();
3705 }
3706
3707 /*!
3708  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3709  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3710  * and are normalized.
3711  * <br> \a this can be either 
3712  * - a  2D mesh in 2D or 3D space or 
3713  * - an 1D mesh in 2D space.
3714  * 
3715  * This method avoids building explicitly a part of \a this mesh to perform the work.
3716  *  \param [in] begin - an array of cell ids of interest.
3717  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3718  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3719  *          cells and one time. The caller is to delete this field using decrRef() as
3720  *          it is no more needed.
3721  *  \throw If the nodal connectivity of cells is not defined.
3722  *  \throw If the coordinates array is not set.
3723  *  \throw If the mesh dimension is not set.
3724  *  \throw If the mesh and space dimension is not as specified above.
3725  *  \sa buildOrthogonalField()
3726  *
3727  *  \if ENABLE_EXAMPLES
3728  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3729  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3730  *  \endif
3731  */
3732 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3733 {
3734   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3735     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3736   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3737   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3738   std::size_t nbelems=std::distance(begin,end);
3739   int nbComp=getMeshDimension()+1;
3740   array->alloc((int)nbelems,nbComp);
3741   double *vals=array->getPointer();
3742   const int *connI=_nodal_connec_index->getConstPointer();
3743   const int *conn=_nodal_connec->getConstPointer();
3744   const double *coords=_coords->getConstPointer();
3745   if(getMeshDimension()==2)
3746     {
3747       if(getSpaceDimension()==3)
3748         {
3749           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3750           const double *locPtr=loc->getConstPointer();
3751           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3752             {
3753               int offset=connI[*i];
3754               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3755               double n=INTERP_KERNEL::norm<3>(vals);
3756               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3757             }
3758         }
3759       else
3760         {
3761           for(std::size_t i=0;i<nbelems;i++)
3762             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3763         }
3764     }
3765   else//meshdimension==1
3766     {
3767       double tmp[2];
3768       for(const int *i=begin;i!=end;i++)
3769         {
3770           int offset=connI[*i];
3771           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3772           double n=INTERP_KERNEL::norm<2>(tmp);
3773           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3774           *vals++=-tmp[1];
3775           *vals++=tmp[0];
3776         }
3777     }
3778   ret->setArray(array);
3779   ret->setMesh(this);
3780   ret->synchronizeTimeWithSupport();
3781   return ret.retn();
3782 }
3783
3784 /*!
3785  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3786  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3787  * and are \b not normalized.
3788  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3789  *          cells and one time. The caller is to delete this field using decrRef() as
3790  *          it is no more needed.
3791  *  \throw If the nodal connectivity of cells is not defined.
3792  *  \throw If the coordinates array is not set.
3793  *  \throw If \a this->getMeshDimension() != 1.
3794  *  \throw If \a this mesh includes cells of type other than SEG2.
3795  */
3796 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3797 {
3798   if(getMeshDimension()!=1)
3799     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3800   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3801     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3802   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3803   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3804   int nbOfCells=getNumberOfCells();
3805   int spaceDim=getSpaceDimension();
3806   array->alloc(nbOfCells,spaceDim);
3807   double *pt=array->getPointer();
3808   const double *coo=getCoords()->getConstPointer();
3809   std::vector<int> conn;
3810   conn.reserve(2);
3811   for(int i=0;i<nbOfCells;i++)
3812     {
3813       conn.resize(0);
3814       getNodeIdsOfCell(i,conn);
3815       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3816     }
3817   ret->setArray(array);
3818   ret->setMesh(this);
3819   ret->synchronizeTimeWithSupport();
3820   return ret.retn();
3821 }
3822
3823 /*!
3824  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3825  * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3826  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3827  * from. If a result face is shared by two 3D cells, then the face in included twice in
3828  * the result mesh.
3829  *  \param [in] origin - 3 components of a point defining location of the plane.
3830  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3831  *         must be greater than 1e-6.
3832  *  \param [in] eps - half-thickness of the plane.
3833  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3834  *         producing correspondent 2D cells. The caller is to delete this array
3835  *         using decrRef() as it is no more needed.
3836  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3837  *         not share the node coordinates array with \a this mesh. The caller is to
3838  *         delete this mesh using decrRef() as it is no more needed.  
3839  *  \throw If the coordinates array is not set.
3840  *  \throw If the nodal connectivity of cells is not defined.
3841  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3842  *  \throw If magnitude of \a vec is less than 1e-6.
3843  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3844  *  \throw If \a this includes quadratic cells.
3845  */
3846 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3847 {
3848   checkFullyDefined();
3849   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3850     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3851   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3852   if(candidates->empty())
3853     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3854   std::vector<int> nodes;
3855   DataArrayInt *cellIds1D=0;
3856   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3857   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3858   MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3859   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3860   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3861   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3862   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3863   revDesc2=0; revDescIndx2=0;
3864   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3865   revDesc1=0; revDescIndx1=0;
3866   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3867   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3868   //
3869   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3870   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3871     cut3DCurve[*it]=-1;
3872   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3873   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3874   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3875                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3876                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3877   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3878   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3879   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3880   if(cellIds2->empty())
3881     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3882   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3883   ret->setCoords(mDesc1->getCoords());
3884   ret->setConnectivity(conn,connI,true);
3885   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3886   return ret.retn();
3887 }
3888
3889 /*!
3890  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3891 addition to the mesh, returns a new DataArrayInt, of length equal to the number of 1D cells in the result mesh, holding, for each cell in the result mesh, an id of a 2D cell it comes
3892 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3893 the result mesh.
3894  *  \param [in] origin - 3 components of a point defining location of the plane.
3895  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3896  *         must be greater than 1e-6.
3897  *  \param [in] eps - half-thickness of the plane.
3898  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3899  *         producing correspondent segments. The caller is to delete this array
3900  *         using decrRef() as it is no more needed.
3901  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3902  *         mesh in 3D space. This mesh does not share the node coordinates array with
3903  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3904  *         no more needed. 
3905  *  \throw If the coordinates array is not set.
3906  *  \throw If the nodal connectivity of cells is not defined.
3907  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3908  *  \throw If magnitude of \a vec is less than 1e-6.
3909  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3910  *  \throw If \a this includes quadratic cells.
3911  */
3912 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3913 {
3914   checkFullyDefined();
3915   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3916     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3917   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3918   if(candidates->empty())
3919     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3920   std::vector<int> nodes;
3921   DataArrayInt *cellIds1D=0;
3922   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3923   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3924   MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3925   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3926   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3927   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3928   MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3929   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3930   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3931   //
3932   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3933   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3934     cut3DCurve[*it]=-1;
3935   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3936   int ncellsSub=subMesh->getNumberOfCells();
3937   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3938   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3939                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3940                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3941   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3942   conn->alloc(0,1);
3943   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3944   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3945   for(int i=0;i<ncellsSub;i++)
3946     {
3947       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3948         {
3949           if(cut3DSurf[i].first!=-2)
3950             {
3951               conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3952               connI->pushBackSilent(conn->getNumberOfTuples());
3953               cellIds2->pushBackSilent(i);
3954             }
3955           else
3956             {
3957               int cellId3DSurf=cut3DSurf[i].second;
3958               int offset=nodalI[cellId3DSurf]+1;
3959               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3960               for(int j=0;j<nbOfEdges;j++)
3961                 {
3962                   conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3963                   connI->pushBackSilent(conn->getNumberOfTuples());
3964                   cellIds2->pushBackSilent(cellId3DSurf);
3965                 }
3966             }
3967         }
3968     }
3969   if(cellIds2->empty())
3970     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3971   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3972   ret->setCoords(mDesc1->getCoords());
3973   ret->setConnectivity(conn,connI,true);
3974   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3975   return ret.retn();
3976 }
3977
3978 /*!
3979  * Finds cells whose bounding boxes intersect a given plane.
3980  *  \param [in] origin - 3 components of a point defining location of the plane.
3981  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3982  *         must be greater than 1e-6.
3983  *  \param [in] eps - half-thickness of the plane.
3984  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3985  *         cells. The caller is to delete this array using decrRef() as it is no more
3986  *         needed.
3987  *  \throw If the coordinates array is not set.
3988  *  \throw If the nodal connectivity of cells is not defined.
3989  *  \throw If \a this->getSpaceDimension() != 3.
3990  *  \throw If magnitude of \a vec is less than 1e-6.
3991  *  \sa buildSlice3D()
3992  */
3993 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3994 {
3995   checkFullyDefined();
3996   if(getSpaceDimension()!=3)
3997     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3998   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3999   if(normm<1e-6)
4000     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4001   double vec2[3];
4002   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4003   double angle=acos(vec[2]/normm);
4004   MCAuto<DataArrayInt> cellIds;
4005   double bbox[6];
4006   if(angle>eps)
4007     {
4008       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4009       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4010       if(normm2/normm>1e-6)
4011         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4012       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4013       mw->setCoords(coo);
4014       mw->getBoundingBox(bbox);
4015       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4016       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4017     }
4018   else
4019     {
4020       getBoundingBox(bbox);
4021       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4022       cellIds=getCellsInBoundingBox(bbox,eps);
4023     }
4024   return cellIds.retn();
4025 }
4026
4027 /*!
4028  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4029  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4030  * No consideration of coordinate is done by this method.
4031  * 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)
4032  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4033  */
4034 bool MEDCouplingUMesh::isContiguous1D() const
4035 {
4036   if(getMeshDimension()!=1)
4037     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4038   int nbCells=getNumberOfCells();
4039   if(nbCells<1)
4040     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4041   const int *connI=_nodal_connec_index->getConstPointer();
4042   const int *conn=_nodal_connec->getConstPointer();
4043   int ref=conn[connI[0]+2];
4044   for(int i=1;i<nbCells;i++)
4045     {
4046       if(conn[connI[i]+1]!=ref)
4047         return false;
4048       ref=conn[connI[i]+2];
4049     }
4050   return true;
4051 }
4052
4053 /*!
4054  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4055  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4056  * \param pt reference point of the line
4057  * \param v normalized director vector of the line
4058  * \param eps max precision before throwing an exception
4059  * \param res output of size this->getNumberOfCells
4060  */
4061 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4062 {
4063   if(getMeshDimension()!=1)
4064     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4065   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4066     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4067   if(getSpaceDimension()!=3)
4068     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4069   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4070   const double *fPtr=f->getArray()->getConstPointer();
4071   double tmp[3];
4072   for(int i=0;i<getNumberOfCells();i++)
4073     {
4074       const double *tmp1=fPtr+3*i;
4075       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4076       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4077       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4078       double n1=INTERP_KERNEL::norm<3>(tmp);
4079       n1/=INTERP_KERNEL::norm<3>(tmp1);
4080       if(n1>eps)
4081         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4082     }
4083   const double *coo=getCoords()->getConstPointer();
4084   for(int i=0;i<getNumberOfNodes();i++)
4085     {
4086       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4087       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4088       res[i]=std::accumulate(tmp,tmp+3,0.);
4089     }
4090 }
4091
4092 /*!
4093  * This method computes the distance from a point \a pt to \a this and the first \a cellId in \a this corresponding to the returned distance. 
4094  * \a this is expected to be a mesh so that its space dimension is equal to its
4095  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4096  * Distance from \a ptBg to \a ptEnd is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates).
4097  *
4098  * WARNING, if there is some orphan nodes in \a this (nodes not fetched by any cells in \a this ( see MEDCouplingUMesh::zipCoords ) ) these nodes will ** not ** been taken
4099  * into account in this method. Only cells and nodes lying on them are considered in the algorithm (even if one of these orphan nodes is closer than returned distance).
4100  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4101  *
4102  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4103  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4104  *
4105  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4106  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4107  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4108  * \return the positive value of the distance.
4109  * \throw if distance from \a ptBg to \a ptEnd is not equal to the space dimension. An exception is also thrown if mesh dimension of \a this is not equal to space
4110  * dimension - 1.
4111  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4112  */
4113 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4114 {
4115   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4116   if(meshDim!=spaceDim-1)
4117     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4118   if(meshDim!=2 && meshDim!=1)
4119     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4120   checkFullyDefined();
4121   if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4122     { std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoint : input point has to have dimension equal to the space dimension of this (" << spaceDim << ") !"; throw INTERP_KERNEL::Exception(oss.str()); }
4123   DataArrayInt *ret1=0;
4124   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4125   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4126   MCAuto<DataArrayInt> ret1Safe(ret1);
4127   cellId=*ret1Safe->begin();
4128   return *ret0->begin();
4129 }
4130
4131 /*!
4132  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4133  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance. 
4134  * WARNING, if there is some orphan nodes in \a this (nodes not fetched by any cells in \a this ( see MEDCouplingUMesh::zipCoords ) ) these nodes will ** not ** been taken
4135  * into account in this method. Only cells and nodes lying on them are considered in the algorithm (even if one of these orphan nodes is closer than returned distance).
4136  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4137  * 
4138  * \a this is expected to be a mesh so that its space dimension is equal to its
4139  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4140  * Number of components of \a pts is expected to be equal to the space dimension. \a this is also expected to be fully defined (connectivity and coordinates).
4141  *
4142  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4143  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4144  *
4145  * \param [in] pts the list of points in which each tuple represents a point
4146  * \param [out] cellIds a newly allocated object that tells for each point in \a pts the first cell id in \a this that minimizes the distance.
4147  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4148  * \throw if number of components of \a pts is not equal to the space dimension.
4149  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4150  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4151  */
4152 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4153 {
4154   if(!pts)
4155     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4156   pts->checkAllocated();
4157   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4158   if(meshDim!=spaceDim-1)
4159     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4160   if(meshDim!=2 && meshDim!=1)
4161     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4162   if(pts->getNumberOfComponents()!=spaceDim)
4163     {
4164       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4165       throw INTERP_KERNEL::Exception(oss.str());
4166     }
4167   checkFullyDefined();
4168   int nbCells=getNumberOfCells();
4169   if(nbCells==0)
4170     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4171   int nbOfPts=pts->getNumberOfTuples();
4172   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4173   MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4174   const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4175   double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4176   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4177   const double *bbox(bboxArr->begin());
4178   switch(spaceDim)
4179   {
4180     case 3:
4181       {
4182         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4183         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4184           {
4185             double x=std::numeric_limits<double>::max();
4186             std::vector<int> elems;
4187             myTree.getMinDistanceOfMax(ptsPtr,x);
4188             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4189             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4190           }
4191         break;
4192       }
4193     case 2:
4194       {
4195         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4196         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4197           {
4198             double x=std::numeric_limits<double>::max();
4199             std::vector<int> elems;
4200             myTree.getMinDistanceOfMax(ptsPtr,x);
4201             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4202             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4203           }
4204         break;
4205       }
4206     default:
4207       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4208   }
4209   cellIds=ret1.retn();
4210   return ret0.retn();
4211 }
4212
4213 /// @cond INTERNAL
4214
4215 /*!
4216  * \param [in] pt the start pointer (included) of the coordinates of the point
4217  * \param [in] cellIdsBg the start pointer (included) of cellIds
4218  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4219  * \param [in] nc nodal connectivity
4220  * \param [in] ncI nodal connectivity index
4221  * \param [in,out] ret0 the min distance between \a this and the external input point
4222  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4223  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4224  */
4225 void MEDCouplingUMesh::DistanceToPoint3DSurfAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId)
4226 {
4227   cellId=-1;
4228   ret0=std::numeric_limits<double>::max();
4229   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4230     {
4231       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4232       {
4233         case INTERP_KERNEL::NORM_TRI3:
4234           {
4235             double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4236             if(tmp<ret0)
4237               { ret0=tmp; cellId=*zeCell; }
4238             break;
4239           }
4240         case INTERP_KERNEL::NORM_QUAD4:
4241         case INTERP_KERNEL::NORM_POLYGON:
4242           {
4243             double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4244             if(tmp<ret0)
4245               { ret0=tmp; cellId=*zeCell; }
4246             break;
4247           }
4248         default:
4249           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4250       }
4251     }
4252 }
4253
4254 /*!
4255  * \param [in] pt the start pointer (included) of the coordinates of the point
4256  * \param [in] cellIdsBg the start pointer (included) of cellIds
4257  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4258  * \param [in] nc nodal connectivity
4259  * \param [in] ncI nodal connectivity index
4260  * \param [in,out] ret0 the min distance between \a this and the external input point
4261  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4262  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4263  */
4264 void MEDCouplingUMesh::DistanceToPoint2DCurveAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId)
4265 {
4266   cellId=-1;
4267   ret0=std::numeric_limits<double>::max();
4268   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4269     {
4270       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4271       {
4272         case INTERP_KERNEL::NORM_SEG2:
4273           {
4274             std::size_t uselessEntry=0;
4275             double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4276             tmp=sqrt(tmp);
4277             if(tmp<ret0)
4278               { ret0=tmp; cellId=*zeCell; }
4279             break;
4280           }
4281         default:
4282           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4283       }
4284     }
4285 }
4286 /// @endcond
4287
4288 /*!
4289  * Finds cells in contact with a ball (i.e. a point with precision). 
4290  * For speed reasons, the INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6 and INTERP_KERNEL::NORM_QUAD8 cells are considered as convex cells to detect if a point is IN or OUT.
4291  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4292  *
4293  * \warning This method is suitable if the caller intends to evaluate only one
4294  *          point, for more points getCellsContainingPoints() is recommended as it is
4295  *          faster. 
4296  *  \param [in] pos - array of coordinates of the ball central point.
4297  *  \param [in] eps - ball radius.
4298  *  \return int - a smallest id of cells being in contact with the ball, -1 in case
4299  *         if there are no such cells.
4300  *  \throw If the coordinates array is not set.
4301  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4302  */
4303 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4304 {
4305   std::vector<int> elts;
4306   getCellsContainingPoint(pos,eps,elts);
4307   if(elts.empty())
4308     return -1;
4309   return elts.front();
4310 }
4311
4312 /*!
4313  * Finds cells in contact with a ball (i.e. a point with precision).
4314  * For speed reasons, the INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6 and INTERP_KERNEL::NORM_QUAD8 cells are considered as convex cells to detect if a point is IN or OUT.
4315  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4316  * \warning This method is suitable if the caller intends to evaluate only one
4317  *          point, for more points getCellsContainingPoints() is recommended as it is
4318  *          faster. 
4319  *  \param [in] pos - array of coordinates of the ball central point.
4320  *  \param [in] eps - ball radius.
4321  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4322  *         before inserting ids.
4323  *  \throw If the coordinates array is not set.
4324  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4325  *
4326  *  \if ENABLE_EXAMPLES
4327  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4328  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4329  *  \endif
4330  */
4331 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4332 {
4333   MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4334   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4335   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4336 }
4337
4338 /// @cond INTERNAL
4339
4340 namespace MEDCoupling
4341 {
4342   template<const int SPACEDIMM>
4343   class DummyClsMCUG
4344   {
4345   public:
4346     static const int MY_SPACEDIM=SPACEDIMM;
4347     static const int MY_MESHDIM=8;
4348     typedef int MyConnType;
4349     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4350     // begin
4351     // useless, but for windows compilation ...
4352     const double* getCoordinatesPtr() const { return 0; }
4353     const int* getConnectivityPtr() const { return 0; }
4354     const int* getConnectivityIndexPtr() const { return 0; }
4355     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4356     // end
4357   };
4358
4359   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4360   {
4361     INTERP_KERNEL::Edge *ret(0);
4362     MCAuto<INTERP_KERNEL::Node> n0(new INTERP_KERNEL::Node(coords2D[2*bg[0]],coords2D[2*bg[0]+1])),n1(new INTERP_KERNEL::Node(coords2D[2*bg[1]],coords2D[2*bg[1]+1]));
4363     m[n0]=bg[0]; m[n1]=bg[1];
4364     switch(typ)
4365     {
4366       case INTERP_KERNEL::NORM_SEG2:
4367         {
4368           ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4369           break;
4370         }
4371       case INTERP_KERNEL::NORM_SEG3:
4372         {
4373           INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4374           INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4375           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4376           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4377           bool colinearity(inters.areColinears());
4378           delete e1; delete e2;
4379           if(colinearity)
4380             { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4381           else
4382             { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4383           break;
4384         }
4385       default:
4386         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4387     }
4388     return ret;
4389   }
4390
4391   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4392   {
4393     INTERP_KERNEL::Edge *ret=0;
4394     switch(typ)
4395     {
4396       case INTERP_KERNEL::NORM_SEG2:
4397         {
4398           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4399           break;
4400         }
4401       case INTERP_KERNEL::NORM_SEG3:
4402         {
4403           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4404           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4405           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4406           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4407           bool colinearity=inters.areColinears();
4408           delete e1; delete e2;
4409           if(colinearity)
4410             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4411           else
4412             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4413           mapp2[bg[2]].second=false;
4414           break;
4415         }
4416       default:
4417         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4418     }
4419     return ret;
4420   }
4421
4422   /*!
4423    * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4424    * the global mesh 'mDesc'.
4425    * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4426    * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4427    */
4428   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4429                                                                    std::map<INTERP_KERNEL::Node *,int>& mapp)
4430   {
4431     mapp.clear();
4432     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.
4433     const double *coo=mDesc->getCoords()->getConstPointer();
4434     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4435     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4436     std::set<int> s;
4437     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4438       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4439     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4440       {
4441         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4442         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4443       }
4444     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4445     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4446       {
4447         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4448         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4449       }
4450     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4451       {
4452         if((*it2).second.second)
4453           mapp[(*it2).second.first]=(*it2).first;
4454         ((*it2).second.first)->decrRef();
4455       }
4456     return ret;
4457   }
4458
4459   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4460   {
4461     if(nodeId>=offset2)
4462       {
4463         int locId=nodeId-offset2;
4464         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4465       }
4466     if(nodeId>=offset1)
4467       {
4468         int locId=nodeId-offset1;
4469         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4470       }
4471     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4472   }
4473
4474   /**
4475    * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4476    */
4477   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4478                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4479                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4480   {
4481     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4482       {
4483         int eltId1=abs(*desc1)-1;
4484         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4485           {
4486             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4487             if(it==mappRev.end())
4488               {
4489                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4490                 mapp[node]=*it1;
4491                 mappRev[*it1]=node;
4492               }
4493           }
4494       }
4495   }
4496 }
4497
4498 /// @endcond
4499
4500 template<int SPACEDIM>
4501 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4502                                                    double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4503 {
4504   elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4505   int *eltsIndexPtr(eltsIndex->getPointer());
4506   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4507   const double *bbox(bboxArr->begin());
4508   int nbOfCells=getNumberOfCells();
4509   const int *conn=_nodal_connec->getConstPointer();
4510   const int *connI=_nodal_connec_index->getConstPointer();
4511   double bb[2*SPACEDIM];
4512   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4513   for(int i=0;i<nbOfPoints;i++)
4514     {
4515       eltsIndexPtr[i+1]=eltsIndexPtr[i];
4516       for(int j=0;j<SPACEDIM;j++)
4517         {
4518           bb[2*j]=pos[SPACEDIM*i+j];
4519           bb[2*j+1]=pos[SPACEDIM*i+j];
4520         }
4521       std::vector<int> candidates;
4522       myTree.getIntersectingElems(bb,candidates);
4523       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4524         {
4525           int sz(connI[(*iter)+1]-connI[*iter]-1);
4526           INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4527           bool status(false);
4528           if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4529             status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4530           else
4531             {
4532               if(SPACEDIM!=2)
4533                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4534               INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4535               INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4536               std::vector<INTERP_KERNEL::Node *> nodes(sz);
4537               INTERP_KERNEL::QuadraticPolygon *pol(0);
4538               for(int j=0;j<sz;j++)
4539                 {
4540                   int nodeId(conn[connI[*iter]+1+j]);
4541                   nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4542                 }
4543               if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4544                 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4545               else
4546                 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4547               INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4548               double a(0.),b(0.),c(0.);
4549               a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4550               status=pol->isInOrOut2(n);
4551               delete pol; n->decrRef();
4552             }
4553           if(status)
4554             {
4555               eltsIndexPtr[i+1]++;
4556               elts->pushBackSilent(*iter);
4557             }
4558         }
4559     }
4560 }
4561 /*!
4562  * Finds cells in contact with several balls (i.e. points with precision).
4563  * This method is an extension of getCellContainingPoint() and
4564  * getCellsContainingPoint() for the case of multiple points.
4565  * For speed reasons, the INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6 and INTERP_KERNEL::NORM_QUAD8 cells are considered as convex cells to detect if a point is IN or OUT.
4566  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4567  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4568  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4569  *         this->getSpaceDimension() * \a nbOfPoints 
4570  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4571  *  \param [in] eps - radius of balls (i.e. the precision).
4572  *  \param [out] elts - vector returning ids of found cells.
4573  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4574  *         dividing cell ids in \a elts into groups each referring to one
4575  *         point. Its every element (except the last one) is an index pointing to the
4576  *         first id of a group of cells. For example cells in contact with the *i*-th
4577  *         point are described by following range of indices:
4578  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4579  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4580  *         Number of cells in contact with the *i*-th point is
4581  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4582  *  \throw If the coordinates array is not set.
4583  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4584  *
4585  *  \if ENABLE_EXAMPLES
4586  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4587  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4588  *  \endif
4589  */
4590 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4591                                                 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4592 {
4593   int spaceDim=getSpaceDimension();
4594   int mDim=getMeshDimension();
4595   if(spaceDim==3)
4596     {
4597       if(mDim==3)
4598         {
4599           const double *coords=_coords->getConstPointer();
4600           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4601         }
4602       /*else if(mDim==2)
4603         {
4604
4605         }*/
4606       else
4607         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4608     }
4609   else if(spaceDim==2)
4610     {
4611       if(mDim==2)
4612         {
4613           const double *coords=_coords->getConstPointer();
4614           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4615         }
4616       else
4617         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4618     }
4619   else if(spaceDim==1)
4620     {
4621       if(mDim==1)
4622         {
4623           const double *coords=_coords->getConstPointer();
4624           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4625         }
4626       else
4627         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4628     }
4629   else
4630     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4631 }
4632
4633 /*!
4634  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4635  * least two its edges intersect each other anywhere except their extremities. An
4636  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4637  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4638  *         cleared before filling in.
4639  *  \param [in] eps - precision.
4640  *  \throw If \a this->getMeshDimension() != 2.
4641  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4642  */
4643 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4644 {
4645   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4646   if(getMeshDimension()!=2)
4647     throw INTERP_KERNEL::Exception(msg);
4648   int spaceDim=getSpaceDimension();
4649   if(spaceDim!=2 && spaceDim!=3)
4650     throw INTERP_KERNEL::Exception(msg);
4651   const int *conn=_nodal_connec->getConstPointer();
4652   const int *connI=_nodal_connec_index->getConstPointer();
4653   int nbOfCells=getNumberOfCells();
4654   std::vector<double> cell2DinS2;
4655   for(int i=0;i<nbOfCells;i++)
4656     {
4657       int offset=connI[i];
4658       int nbOfNodesForCell=connI[i+1]-offset-1;
4659       if(nbOfNodesForCell<=3)
4660         continue;
4661       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4662       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4663       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4664         cells.push_back(i);
4665       cell2DinS2.clear();
4666     }
4667 }
4668
4669 /*!
4670  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4671  *
4672  * 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.
4673  * 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.
4674  * 
4675  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4676  * This convex envelop is computed using Jarvis march algorithm.
4677  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4678  * 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)
4679  * 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.
4680  *
4681  * \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.
4682  * \sa MEDCouplingUMesh::colinearize2D
4683  */
4684 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4685 {
4686   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4687     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4688   checkFullyDefined();
4689   const double *coords=getCoords()->getConstPointer();
4690   int nbOfCells=getNumberOfCells();
4691   MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4692   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4693   MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4694   int *workIndexOut=nodalConnecIndexOut->getPointer();
4695   *workIndexOut=0;
4696   const int *nodalConnecIn=_nodal_connec->getConstPointer();
4697   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4698   std::set<INTERP_KERNEL::NormalizedCellType> types;
4699   MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4700   isChanged->alloc(0,1);
4701   for(int i=0;i<nbOfCells;i++,workIndexOut++)
4702     {
4703       int pos=nodalConnecOut->getNumberOfTuples();
4704       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4705         isChanged->pushBackSilent(i);
4706       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4707       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4708     }
4709   if(isChanged->empty())
4710     return 0;
4711   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4712   _types=types;
4713   return isChanged.retn();
4714 }
4715
4716 /*!
4717  * This method is \b NOT const because it can modify \a this.
4718  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4719  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4720  * \param policy specifies the type of extrusion chosen:
4721  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4722  *   will be repeated to build each level
4723  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4724  *   the 3 preceding points of the 1D mesh. The center of the arc is the center of rotation for each level, the rotation is done
4725  *   along an axis normal to the plane containing the arc, and finally the angle of rotation is defined by the first two points on the
4726  *   arc.
4727  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.  
4728  */
4729 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4730 {
4731   checkFullyDefined();
4732   mesh1D->checkFullyDefined();
4733   if(!mesh1D->isContiguous1D())
4734     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4735   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4736     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4737   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4738     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4739   if(mesh1D->getMeshDimension()!=1)
4740     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4741   bool isQuad=false;
4742   if(isPresenceOfQuadratic())
4743     {
4744       if(mesh1D->isFullyQuadratic())
4745         isQuad=true;
4746       else
4747         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4748     }
4749   int oldNbOfNodes(getNumberOfNodes());
4750   MCAuto<DataArrayDouble> newCoords;
4751   switch(policy)
4752   {
4753     case 0:
4754       {
4755         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4756         break;
4757       }
4758     case 1:
4759       {
4760         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4761         break;
4762       }
4763     default:
4764       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4765   }
4766   setCoords(newCoords);
4767   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4768   updateTime();
4769   return ret.retn();
4770 }
4771
4772 /*!
4773  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4774  * If it is not the case an exception will be thrown.
4775  * This method is non const because the coordinate of \a this can be appended with some new points issued from
4776  * intersection of plane defined by ('origin','vec').
4777  * This method has one in/out parameter : 'cut3DCurve'.
4778  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4779  * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4780  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4781  * This method will throw an exception if \a this contains a non linear segment.
4782  */
4783 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4784 {
4785   checkFullyDefined();
4786   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4787     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4788   int ncells=getNumberOfCells();
4789   int nnodes=getNumberOfNodes();
4790   double vec2[3],vec3[3],vec4[3];
4791   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4792   if(normm<1e-6)
4793     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4794   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4795   const int *conn=_nodal_connec->getConstPointer();
4796   const int *connI=_nodal_connec_index->getConstPointer();
4797   const double *coo=_coords->getConstPointer();
4798   std::vector<double> addCoo;
4799   for(int i=0;i<ncells;i++)
4800     {
4801       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4802         {
4803           if(cut3DCurve[i]==-2)
4804             {
4805               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4806               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];
4807               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4808               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4809               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4810                 {
4811                   const double *st2=coo+3*st;
4812                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4813                   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]));
4814                   if(pos>eps && pos<1-eps)
4815                     {
4816                       int nNode=((int)addCoo.size())/3;
4817                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4818                       addCoo.insert(addCoo.end(),vec4,vec4+3);
4819                       cut3DCurve[i]=nnodes+nNode;
4820                     }
4821                 }
4822             }
4823         }
4824       else
4825         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4826     }
4827   if(!addCoo.empty())
4828     {
4829       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4830       MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4831       coo2->alloc(newNbOfNodes,3);
4832       double *tmp=coo2->getPointer();
4833       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4834       std::copy(addCoo.begin(),addCoo.end(),tmp);
4835       DataArrayDouble::SetArrayIn(coo2,_coords);
4836     }
4837 }
4838
4839 /*!
4840  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4841  * \param mesh1D is the input 1D mesh used for translation computation.
4842  * \return newCoords new coords filled by this method. 
4843  */
4844 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4845 {
4846   int oldNbOfNodes=getNumberOfNodes();
4847   int nbOf1DCells=mesh1D->getNumberOfCells();
4848   int spaceDim=getSpaceDimension();
4849   DataArrayDouble *ret=DataArrayDouble::New();
4850   std::vector<bool> isQuads;
4851   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4852   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4853   double *retPtr=ret->getPointer();
4854   const double *coords=getCoords()->getConstPointer();
4855   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4856   std::vector<int> v;
4857   std::vector<double> c;
4858   double vec[3];
4859   v.reserve(3);
4860   c.reserve(6);
4861   for(int i=0;i<nbOf1DCells;i++)
4862     {
4863       v.resize(0);
4864       mesh1D->getNodeIdsOfCell(i,v);
4865       c.resize(0);
4866       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4867       mesh1D->getCoordinatesOfNode(v[0],c);
4868       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4869       for(int j=0;j<oldNbOfNodes;j++)
4870         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4871       if(isQuad)
4872         {
4873           c.resize(0);
4874           mesh1D->getCoordinatesOfNode(v[1],c);
4875           mesh1D->getCoordinatesOfNode(v[0],c);
4876           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4877           for(int j=0;j<oldNbOfNodes;j++)
4878             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4879         }
4880     }
4881   ret->copyStringInfoFrom(*getCoords());
4882   return ret;
4883 }
4884
4885 /*!
4886  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4887  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4888  * \return newCoords new coords filled by this method. 
4889  */
4890 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4891 {
4892   if(mesh1D->getSpaceDimension()==2)
4893     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4894   if(mesh1D->getSpaceDimension()==3)
4895     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4896   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4897 }
4898
4899 /*!
4900  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4901  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4902  * \return newCoords new coords filled by this method. 
4903  */
4904 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4905 {
4906   if(isQuad)
4907     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4908   int oldNbOfNodes=getNumberOfNodes();
4909   int nbOf1DCells=mesh1D->getNumberOfCells();
4910   if(nbOf1DCells<2)
4911     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4912   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4913   int nbOfLevsInVec=nbOf1DCells+1;
4914   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4915   double *retPtr=ret->getPointer();
4916   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4917   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4918   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4919   tmp->setCoords(tmp2);
4920   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4921   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4922   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4923   for(int i=1;i<nbOfLevsInVec;i++)
4924     {
4925       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4926       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4927       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4928       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4929       tmp->translate(vec);
4930       double tmp3[2],radius,alpha,alpha0;
4931       const double *p0=i+1<nbOfLevsInVec?begin:third;
4932       const double *p1=i+1<nbOfLevsInVec?end:begin;
4933       const double *p2=i+1<nbOfLevsInVec?third:end;
4934       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4935       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]);
4936       double angle=acos(cosangle/(radius*radius));
4937       tmp->rotate(end,0,angle);
4938       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4939     }
4940   return ret.retn();
4941 }
4942
4943 /*!
4944  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4945  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4946  * \return newCoords new coords filled by this method. 
4947  */
4948 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4949 {
4950   if(isQuad)
4951     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4952   int oldNbOfNodes=getNumberOfNodes();
4953   int nbOf1DCells=mesh1D->getNumberOfCells();
4954   if(nbOf1DCells<2)
4955     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4956   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4957   int nbOfLevsInVec=nbOf1DCells+1;
4958   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4959   double *retPtr=ret->getPointer();
4960   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4961   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4962   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4963   tmp->setCoords(tmp2);
4964   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4965   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4966   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4967   for(int i=1;i<nbOfLevsInVec;i++)
4968     {
4969       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4970       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4971       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4972       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4973       tmp->translate(vec);
4974       double tmp3[2],radius,alpha,alpha0;
4975       const double *p0=i+1<nbOfLevsInVec?begin:third;
4976       const double *p1=i+1<nbOfLevsInVec?end:begin;
4977       const double *p2=i+1<nbOfLevsInVec?third:end;
4978       double vecPlane[3]={
4979         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4980         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4981         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4982       };
4983       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4984       if(norm>1.e-7)
4985         {
4986           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4987           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4988           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4989           double s2=norm2;
4990           double c2=cos(asin(s2));
4991           double m[3][3]={
4992             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4993             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4994             {-vec2[1]*s2, vec2[0]*s2, c2}
4995           };
4996           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]};
4997           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]};
4998           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]};
4999           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
5000           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]);
5001           double angle=acos(cosangle/(radius*radius));
5002           tmp->rotate(end,vecPlane,angle);
5003         }
5004       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
5005     }
5006   return ret.retn();
5007 }
5008
5009 /*!
5010  * This method is private because not easy to use for end user. This method is const contrary to
5011  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
5012  * the coords sorted slice by slice.
5013  * \param isQuad specifies presence of quadratic cells.
5014  */
5015 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
5016 {
5017   int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
5018   int nbOf2DCells(getNumberOfCells());
5019   int nbOf3DCells(nbOf2DCells*nbOf1DCells);
5020   MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
5021   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5022   MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
5023   newConnI->alloc(nbOf3DCells+1,1);
5024   int *newConnIPtr(newConnI->getPointer());
5025   *newConnIPtr++=0;
5026   std::vector<int> newc;
5027   for(int j=0;j<nbOf2DCells;j++)
5028     {
5029       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5030       *newConnIPtr++=(int)newc.size();
5031     }
5032   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5033   int *newConnPtr(newConn->getPointer());
5034   int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5035   newConnIPtr=newConnI->getPointer();
5036   for(int iz=0;iz<nbOf1DCells;iz++)
5037     {
5038       if(iz!=0)
5039         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5040       const int *posOfTypeOfCell(newConnIPtr);
5041       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5042         {
5043           int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5044           if(icell!=*posOfTypeOfCell)
5045             {
5046               if(*iter!=-1)
5047                 *newConnPtr=(*iter)+iz*deltaPerLev;
5048               else
5049                 *newConnPtr=-1;
5050             }
5051           else
5052             {
5053               *newConnPtr=*iter;
5054               posOfTypeOfCell++;
5055             }
5056         }
5057     }
5058   ret->setConnectivity(newConn,newConnI,true);
5059   ret->setCoords(getCoords());
5060   return ret;
5061 }
5062
5063 /*!
5064  * Checks if \a this mesh is constituted by only quadratic cells.
5065  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
5066  *  \throw If the coordinates array is not set.
5067  *  \throw If the nodal connectivity of cells is not defined.
5068  */
5069 bool MEDCouplingUMesh::isFullyQuadratic() const
5070 {
5071   checkFullyDefined();
5072   bool ret=true;
5073   int nbOfCells=getNumberOfCells();
5074   for(int i=0;i<nbOfCells && ret;i++)
5075     {
5076       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5077       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5078       ret=cm.isQuadratic();
5079     }
5080   return ret;
5081 }
5082
5083 /*!
5084  * Checks if \a this mesh includes any quadratic cell.
5085  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5086  *  \throw If the coordinates array is not set.
5087  *  \throw If the nodal connectivity of cells is not defined.
5088  */
5089 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5090 {
5091   checkFullyDefined();
5092   bool ret=false;
5093   int nbOfCells=getNumberOfCells();
5094   for(int i=0;i<nbOfCells && !ret;i++)
5095     {
5096       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5097       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5098       ret=cm.isQuadratic();
5099     }
5100   return ret;
5101 }
5102
5103 /*!
5104  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5105  * this mesh, it remains unchanged.
5106  *  \throw If the coordinates array is not set.
5107  *  \throw If the nodal connectivity of cells is not defined.
5108  */
5109 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5110 {
5111   checkFullyDefined();
5112   int nbOfCells=getNumberOfCells();
5113   int delta=0;
5114   const int *iciptr=_nodal_connec_index->getConstPointer();
5115   for(int i=0;i<nbOfCells;i++)
5116     {
5117       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5118       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5119       if(cm.isQuadratic())
5120         {
5121           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5122           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5123           if(!cml.isDynamic())
5124             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5125           else
5126             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5127         }
5128     }
5129   if(delta==0)
5130     return ;
5131   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5132   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5133   const int *icptr=_nodal_connec->getConstPointer();
5134   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5135   newConnI->alloc(nbOfCells+1,1);
5136   int *ocptr=newConn->getPointer();
5137   int *ociptr=newConnI->getPointer();
5138   *ociptr=0;
5139   _types.clear();
5140   for(int i=0;i<nbOfCells;i++,ociptr++)
5141     {
5142       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5143       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5144       if(!cm.isQuadratic())
5145         {
5146           _types.insert(type);
5147           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5148           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5149         }
5150       else
5151         {
5152           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5153           _types.insert(typel);
5154           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5155           int newNbOfNodes=cml.getNumberOfNodes();
5156           if(cml.isDynamic())
5157             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5158           *ocptr++=(int)typel;
5159           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5160           ociptr[1]=ociptr[0]+newNbOfNodes+1;
5161         }
5162     }
5163   setConnectivity(newConn,newConnI,false);
5164 }
5165
5166 /*!
5167  * This method converts all linear cell in \a this to quadratic one.
5168  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5169  * type of cells expected. For example INTERP_KERNEL::NORM_TRI3 can be converted to INTERP_KERNEL::NORM_TRI6 if \a conversionType is equal to 0 (the default)
5170  * or to INTERP_KERNEL::NORM_TRI7 if \a conversionType is equal to 1. All non linear cells and polyhedron in \a this are let untouched.
5171  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5172  * end of the existing coordinates.
5173  * 
5174  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5175  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
5176  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5177  * 
5178  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5179  *
5180  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5181  */
5182 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5183 {
5184   DataArrayInt *conn=0,*connI=0;
5185   DataArrayDouble *coords=0;
5186   std::set<INTERP_KERNEL::NormalizedCellType> types;
5187   checkFullyDefined();
5188   MCAuto<DataArrayInt> ret,connSafe,connISafe;
5189   MCAuto<DataArrayDouble> coordsSafe;
5190   int meshDim=getMeshDimension();
5191   switch(conversionType)
5192   {
5193     case 0:
5194       switch(meshDim)
5195       {
5196         case 1:
5197           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5198           connSafe=conn; connISafe=connI; coordsSafe=coords;
5199           break;
5200         case 2:
5201           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5202           connSafe=conn; connISafe=connI; coordsSafe=coords;
5203           break;
5204         case 3:
5205           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5206           connSafe=conn; connISafe=connI; coordsSafe=coords;
5207           break;
5208         default:
5209           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5210       }
5211       break;
5212         case 1:
5213           {
5214             switch(meshDim)
5215             {
5216               case 1:
5217                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5218                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5219                 break;
5220               case 2:
5221                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5222                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5223                 break;
5224               case 3:
5225                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5226                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5227                 break;
5228               default:
5229                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5230             }
5231             break;
5232           }
5233         default:
5234           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5235   }
5236   setConnectivity(connSafe,connISafe,false);
5237   _types=types;
5238   setCoords(coordsSafe);
5239   return ret.retn();
5240 }
5241
5242 /*!
5243  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5244  * so that the number of cells remains the same. Quadratic faces are converted to
5245  * polygons. This method works only for 2D meshes in
5246  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5247  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5248  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5249  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5250  *         a polylinized edge constituting the input polygon.
5251  *  \throw If the coordinates array is not set.
5252  *  \throw If the nodal connectivity of cells is not defined.
5253  *  \throw If \a this->getMeshDimension() != 2.
5254  *  \throw If \a this->getSpaceDimension() != 2.
5255  */
5256 void MEDCouplingUMesh::tessellate2D(double eps)
5257 {
5258   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5259   if(spaceDim!=2)
5260     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5261   switch(meshDim)
5262     {
5263     case 1:
5264       return tessellate2DCurveInternal(eps);
5265     case 2:
5266       return tessellate2DInternal(eps);
5267     default:
5268       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5269     }
5270 }
5271 /*!
5272  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5273  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5274  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5275  *         a sub-divided edge.
5276  *  \throw If the coordinates array is not set.
5277  *  \throw If the nodal connectivity of cells is not defined.
5278  *  \throw If \a this->getMeshDimension() != 1.
5279  *  \throw If \a this->getSpaceDimension() != 2.
5280  */
5281
5282 #if 0
5283 /*!
5284  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5285  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5286  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
5287  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5288  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5289  * This method can be seen as the opposite method of colinearize2D.
5290  * This method can be lead to create some new nodes if quadratic polygon cells have to be split. In this case the added nodes will be put at the end
5291  * to avoid to modify the numbering of existing nodes.
5292  *
5293  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5294  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5295  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5296  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5297  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5298  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5299  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5300  *
5301  * \sa buildDescendingConnectivity2
5302  */
5303 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5304                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5305 {
5306   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5307     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5308   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5309   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5310     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5311   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5312     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5313   //DataArrayInt *out0(0),*outi0(0);
5314   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5315   //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5316   //out0s=out0s->buildUnique(); out0s->sort(true);
5317 }
5318 #endif
5319
5320 /*!
5321  * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5322  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5323  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5324  */
5325 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5326 {
5327   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5328   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5329   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5330   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5331   int nbOfCells=getNumberOfCells();
5332   int nbOfNodes=getNumberOfNodes();
5333   const int *cPtr=_nodal_connec->getConstPointer();
5334   const int *icPtr=_nodal_connec_index->getConstPointer();
5335   int lastVal=0,offset=nbOfNodes;
5336   for(int i=0;i<nbOfCells;i++,icPtr++)
5337     {
5338       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5339       if(type==INTERP_KERNEL::NORM_SEG2)
5340         {
5341           types.insert(INTERP_KERNEL::NORM_SEG3);
5342           newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5343           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5344           newConn->pushBackSilent(offset++);
5345           lastVal+=4;
5346           newConnI->pushBackSilent(lastVal);
5347           ret->pushBackSilent(i);
5348         }
5349       else
5350         {
5351           types.insert(type);
5352           lastVal+=(icPtr[1]-icPtr[0]);
5353           newConnI->pushBackSilent(lastVal);
5354           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5355         }
5356     }
5357   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5358   coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5359   return ret.retn();
5360 }
5361
5362 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2DAnd3D0(const MEDCouplingUMesh *m1D, const DataArrayInt *desc, const DataArrayInt *descI, DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5363 {
5364   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5365   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5366   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5367   //
5368   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5369   DataArrayInt *conn1D=0,*conn1DI=0;
5370   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5371   DataArrayDouble *coordsTmp=0;
5372   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5373   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5374   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5375   const int *c1DPtr=conn1D->begin();
5376   const int *c1DIPtr=conn1DI->begin();
5377   int nbOfCells=getNumberOfCells();
5378   const int *cPtr=_nodal_connec->getConstPointer();
5379   const int *icPtr=_nodal_connec_index->getConstPointer();
5380   int lastVal=0;
5381   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5382     {
5383       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5384       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5385       if(!cm.isQuadratic())
5386         {
5387           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5388           types.insert(typ2); newConn->pushBackSilent(typ2);
5389           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5390           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5391             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5392           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5393           newConnI->pushBackSilent(lastVal);
5394           ret->pushBackSilent(i);
5395         }
5396       else
5397         {
5398           types.insert(typ);
5399           lastVal+=(icPtr[1]-icPtr[0]);
5400           newConnI->pushBackSilent(lastVal);
5401           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5402         }
5403     }
5404   conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5405   return ret.retn();
5406 }
5407
5408 /*!
5409  * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5410  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5411  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5412  */
5413 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5414 {
5415   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5416   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5417   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5418 }
5419
5420 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5421 {
5422   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5423   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5424   //
5425   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5426   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5427   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5428   //
5429   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5430   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5431   DataArrayInt *conn1D=0,*conn1DI=0;
5432   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5433   DataArrayDouble *coordsTmp=0;
5434   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5435   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5436   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5437   const int *c1DPtr=conn1D->begin();
5438   const int *c1DIPtr=conn1DI->begin();
5439   int nbOfCells=getNumberOfCells();
5440   const int *cPtr=_nodal_connec->getConstPointer();
5441   const int *icPtr=_nodal_connec_index->getConstPointer();
5442   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5443   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5444     {
5445       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5446       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5447       if(!cm.isQuadratic())
5448         {
5449           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5450           types.insert(typ2); newConn->pushBackSilent(typ2);
5451           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5452           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5453             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5454           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5455           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5456           newConnI->pushBackSilent(lastVal);
5457           ret->pushBackSilent(i);
5458         }
5459       else
5460         {
5461           types.insert(typ);
5462           lastVal+=(icPtr[1]-icPtr[0]);
5463           newConnI->pushBackSilent(lastVal);
5464           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5465         }
5466     }
5467   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5468   coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5469   return ret.retn();
5470 }
5471
5472 /*!
5473  * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5474  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5475  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5476  */
5477 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5478 {
5479   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5480   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5481   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5482 }
5483
5484 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5485 {
5486   MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5487   MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5488   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5489   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5490   //
5491   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5492   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5493   MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5494   //
5495   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5496   const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5497   DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5498   std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5499   DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5500   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5501   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5502   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5503   MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5504   MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5505   MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5506   const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5507   int nbOfCells=getNumberOfCells();
5508   const int *cPtr=_nodal_connec->getConstPointer();
5509   const int *icPtr=_nodal_connec_index->getConstPointer();
5510   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5511   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5512     {
5513       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5514       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5515       if(!cm.isQuadratic())
5516         {
5517           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5518           if(typ2==INTERP_KERNEL::NORM_ERROR)
5519             {
5520               std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5521               throw INTERP_KERNEL::Exception(oss.str());
5522             }
5523           types.insert(typ2); newConn->pushBackSilent(typ2);
5524           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5525           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5526             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5527           for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5528             {
5529               int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5530               int tmpPos=newConn->getNumberOfTuples();
5531               newConn->pushBackSilent(nodeId2);
5532               ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5533             }
5534           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5535           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5536           newConnI->pushBackSilent(lastVal);
5537           ret->pushBackSilent(i);
5538         }
5539       else
5540         {
5541           types.insert(typ);
5542           lastVal+=(icPtr[1]-icPtr[0]);
5543           newConnI->pushBackSilent(lastVal);
5544           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5545         }
5546     }
5547   MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5548   MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5549   coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5550   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5551   std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5552   int *c=newConn->getPointer();
5553   const int *cI(newConnI->begin());
5554   for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5555     c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5556   offset=coordsTmp2Safe->getNumberOfTuples();
5557   for(const int *elt=ret->begin();elt!=ret->end();elt++)
5558     c[cI[(*elt)+1]-1]+=offset;
5559   coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5560   return ret.retn();
5561 }
5562
5563 /*!
5564  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5565  * In addition, returns an array mapping new cells to old ones. <br>
5566  * This method typically increases the number of cells in \a this mesh
5567  * but the number of nodes remains \b unchanged.
5568  * That's why the 3D splitting policies
5569  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5570  *  \param [in] policy - specifies a pattern used for splitting.
5571  * The semantic of \a policy is:
5572  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5573  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5574  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5575  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5576  *
5577  *
5578  *  \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5579  *          an id of old cell producing it. The caller is to delete this array using
5580  *         decrRef() as it is no more needed.
5581  *
5582  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5583  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5584  *          and \a this->getMeshDimension() != 3. 
5585  *  \throw If \a policy is not one of the four discussed above.
5586  *  \throw If the nodal connectivity of cells is not defined.
5587  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5588  */
5589 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5590 {
5591   switch(policy)
5592   {
5593     case 0:
5594       return simplexizePol0();
5595     case 1:
5596       return simplexizePol1();
5597     case (int) INTERP_KERNEL::PLANAR_FACE_5:
5598         return simplexizePlanarFace5();
5599     case (int) INTERP_KERNEL::PLANAR_FACE_6:
5600         return simplexizePlanarFace6();
5601     default:
5602       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexize : unrecognized policy ! Must be :\n  - 0 or 1 (only available for meshdim=2) \n  - PLANAR_FACE_5, PLANAR_FACE_6  (only for meshdim=3)");
5603   }
5604 }
5605
5606 /*!
5607  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5608  * - 1D: INTERP_KERNEL::NORM_SEG2
5609  * - 2D: INTERP_KERNEL::NORM_TRI3
5610  * - 3D: INTERP_KERNEL::NORM_TETRA4.
5611  *
5612  * This method is useful for users that need to use P1 field services as
5613  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5614  * All these methods need mesh support containing only simplex cells.
5615  *  \return bool - \c true if there are only simplex cells in \a this mesh.
5616  *  \throw If the coordinates array is not set.
5617  *  \throw If the nodal connectivity of cells is not defined.
5618  *  \throw If \a this->getMeshDimension() < 1.
5619  */
5620 bool MEDCouplingUMesh::areOnlySimplexCells() const
5621 {
5622   checkFullyDefined();
5623   int mdim=getMeshDimension();
5624   if(mdim<1 || mdim>3)
5625     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5626   int nbCells=getNumberOfCells();
5627   const int *conn=_nodal_connec->getConstPointer();
5628   const int *connI=_nodal_connec_index->getConstPointer();
5629   for(int i=0;i<nbCells;i++)
5630     {
5631       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5632       if(!cm.isSimplex())
5633         return false;
5634     }
5635   return true;
5636 }
5637
5638 /*!
5639  * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5640  */
5641 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5642 {
5643   checkConnectivityFullyDefined();
5644   if(getMeshDimension()!=2)
5645     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5646   int nbOfCells=getNumberOfCells();
5647   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5648   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5649   ret->alloc(nbOfCells+nbOfCutCells,1);
5650   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5651   int *retPt=ret->getPointer();
5652   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5653   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5654   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5655   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5656   int *pt=newConn->getPointer();
5657   int *ptI=newConnI->getPointer();
5658   ptI[0]=0;
5659   const int *oldc=_nodal_connec->getConstPointer();
5660   const int *ci=_nodal_connec_index->getConstPointer();
5661   for(int i=0;i<nbOfCells;i++,ci++)
5662     {
5663       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5664         {
5665           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5666             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5667           pt=std::copy(tmp,tmp+8,pt);
5668           ptI[1]=ptI[0]+4;
5669           ptI[2]=ptI[0]+8;
5670           *retPt++=i;
5671           *retPt++=i;
5672           ptI+=2;
5673         }
5674       else
5675         {
5676           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5677           ptI[1]=ptI[0]+ci[1]-ci[0];
5678           ptI++;
5679           *retPt++=i;
5680         }
5681     }
5682   _nodal_connec->decrRef();
5683   _nodal_connec=newConn.retn();
5684   _nodal_connec_index->decrRef();
5685   _nodal_connec_index=newConnI.retn();
5686   computeTypes();
5687   updateTime();
5688   return ret.retn();
5689 }
5690
5691 /*!
5692  * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5693  */
5694 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5695 {
5696   checkConnectivityFullyDefined();
5697   if(getMeshDimension()!=2)
5698     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5699   int nbOfCells=getNumberOfCells();
5700   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5701   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5702   ret->alloc(nbOfCells+nbOfCutCells,1);
5703   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5704   int *retPt=ret->getPointer();
5705   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5706   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5707   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5708   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5709   int *pt=newConn->getPointer();
5710   int *ptI=newConnI->getPointer();
5711   ptI[0]=0;
5712   const int *oldc=_nodal_connec->getConstPointer();
5713   const int *ci=_nodal_connec_index->getConstPointer();
5714   for(int i=0;i<nbOfCells;i++,ci++)
5715     {
5716       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5717         {
5718           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5719             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5720           pt=std::copy(tmp,tmp+8,pt);
5721           ptI[1]=ptI[0]+4;
5722           ptI[2]=ptI[0]+8;
5723           *retPt++=i;
5724           *retPt++=i;
5725           ptI+=2;
5726         }
5727       else
5728         {
5729           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5730           ptI[1]=ptI[0]+ci[1]-ci[0];
5731           ptI++;
5732           *retPt++=i;
5733         }
5734     }
5735   _nodal_connec->decrRef();
5736   _nodal_connec=newConn.retn();
5737   _nodal_connec_index->decrRef();
5738   _nodal_connec_index=newConnI.retn();
5739   computeTypes();
5740   updateTime();
5741   return ret.retn();
5742 }
5743
5744 /*!
5745  * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5746  */
5747 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5748 {
5749   checkConnectivityFullyDefined();
5750   if(getMeshDimension()!=3)
5751     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5752   int nbOfCells=getNumberOfCells();
5753   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5754   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5755   ret->alloc(nbOfCells+4*nbOfCutCells,1);
5756   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5757   int *retPt=ret->getPointer();
5758   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5759   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5760   newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5761   newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5762   int *pt=newConn->getPointer();
5763   int *ptI=newConnI->getPointer();
5764   ptI[0]=0;
5765   const int *oldc=_nodal_connec->getConstPointer();
5766   const int *ci=_nodal_connec_index->getConstPointer();
5767   for(int i=0;i<nbOfCells;i++,ci++)
5768     {
5769       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5770         {
5771           for(int j=0;j<5;j++,pt+=5,ptI++)
5772             {
5773               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5774               pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+3]+1];
5775               *retPt++=i;
5776               ptI[1]=ptI[0]+5;
5777             }
5778         }
5779       else
5780         {
5781           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5782           ptI[1]=ptI[0]+ci[1]-ci[0];
5783           ptI++;
5784           *retPt++=i;
5785         }
5786     }
5787   _nodal_connec->decrRef();
5788   _nodal_connec=newConn.retn();
5789   _nodal_connec_index->decrRef();
5790   _nodal_connec_index=newConnI.retn();
5791   computeTypes();
5792   updateTime();
5793   return ret.retn();
5794 }
5795
5796 /*!
5797  * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5798  */
5799 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5800 {
5801   checkConnectivityFullyDefined();
5802   if(getMeshDimension()!=3)
5803     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5804   int nbOfCells=getNumberOfCells();
5805   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5806   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5807   ret->alloc(nbOfCells+5*nbOfCutCells,1);
5808   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5809   int *retPt=ret->getPointer();
5810   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5811   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5812   newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5813   newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5814   int *pt=newConn->getPointer();
5815   int *ptI=newConnI->getPointer();
5816   ptI[0]=0;
5817   const int *oldc=_nodal_connec->getConstPointer();
5818   const int *ci=_nodal_connec_index->getConstPointer();
5819   for(int i=0;i<nbOfCells;i++,ci++)
5820     {
5821       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5822         {
5823           for(int j=0;j<6;j++,pt+=5,ptI++)
5824             {
5825               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5826               pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+3]+1];
5827               *retPt++=i;
5828               ptI[1]=ptI[0]+5;
5829             }
5830         }
5831       else
5832         {
5833           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5834           ptI[1]=ptI[0]+ci[1]-ci[0];
5835           ptI++;
5836           *retPt++=i;
5837         }
5838     }
5839   _nodal_connec->decrRef();
5840   _nodal_connec=newConn.retn();
5841   _nodal_connec_index->decrRef();
5842   _nodal_connec_index=newConnI.retn();
5843   computeTypes();
5844   updateTime();
5845   return ret.retn();
5846 }
5847
5848 /*!
5849  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5850  * so that the number of cells remains the same. Quadratic faces are converted to
5851  * polygons. This method works only for 2D meshes in
5852  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5853  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5854  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5855  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5856  *         a polylinized edge constituting the input polygon.
5857  *  \throw If the coordinates array is not set.
5858  *  \throw If the nodal connectivity of cells is not defined.
5859  *  \throw If \a this->getMeshDimension() != 2.
5860  *  \throw If \a this->getSpaceDimension() != 2.
5861  */
5862 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5863 {
5864   checkFullyDefined();
5865   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
5866     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5867   double epsa=fabs(eps);
5868   if(epsa<std::numeric_limits<double>::min())
5869     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5870   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5871   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5872   revDesc1=0; revDescIndx1=0;
5873   mDesc->tessellate2D(eps);
5874   subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5875   setCoords(mDesc->getCoords());
5876 }
5877
5878 /*!
5879  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5880  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5881  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5882  *         a sub-divided edge.
5883  *  \throw If the coordinates array is not set.
5884  *  \throw If the nodal connectivity of cells is not defined.
5885  *  \throw If \a this->getMeshDimension() != 1.
5886  *  \throw If \a this->getSpaceDimension() != 2.
5887  */
5888 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5889 {
5890   checkFullyDefined();
5891   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5892     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5893   double epsa=fabs(eps);
5894   if(epsa<std::numeric_limits<double>::min())
5895     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5896   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5897   int nbCells=getNumberOfCells();
5898   int nbNodes=getNumberOfNodes();
5899   const int *conn=_nodal_connec->getConstPointer();
5900   const int *connI=_nodal_connec_index->getConstPointer();
5901   const double *coords=_coords->getConstPointer();
5902   std::vector<double> addCoo;
5903   std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5904   MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5905   newConnI->alloc(nbCells+1,1);
5906   int *newConnIPtr=newConnI->getPointer();
5907   *newConnIPtr=0;
5908   int tmp1[3];
5909   INTERP_KERNEL::Node *tmp2[3];
5910   std::set<INTERP_KERNEL::NormalizedCellType> types;
5911   for(int i=0;i<nbCells;i++,newConnIPtr++)
5912     {
5913       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5914       if(cm.isQuadratic())
5915         {//assert(connI[i+1]-connI[i]-1==3)
5916           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5917           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5918           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5919           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5920           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5921           if(eac)
5922             {
5923               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5924               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5925               delete eac;
5926               newConnIPtr[1]=(int)newConn.size();
5927             }
5928           else
5929             {
5930               types.insert(INTERP_KERNEL::NORM_SEG2);
5931               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5932               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5933               newConnIPtr[1]=newConnIPtr[0]+3;
5934             }
5935         }
5936       else
5937         {
5938           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5939           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5940           newConnIPtr[1]=newConnIPtr[0]+3;
5941         }
5942     }
5943   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5944     return ;
5945   _types=types;
5946   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5947   MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5948   newConnArr->alloc((int)newConn.size(),1);
5949   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5950   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5951   MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5952   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5953   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5954   std::copy(addCoo.begin(),addCoo.end(),work);
5955   DataArrayDouble::SetArrayIn(newCoords,_coords);
5956   updateTime();
5957 }
5958
5959 /*!
5960  * This private method is used to subdivide edges of a mesh with meshdim==2. If \a this has no a meshdim equal to 2 an exception will be thrown.
5961  * This method completly ignore coordinates.
5962  * \param nodeSubdived is the nodal connectivity of subdivision of edges
5963  * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5964  * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5965  * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5966  */
5967 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5968 {
5969   checkFullyDefined();
5970   if(getMeshDimension()!=2)
5971     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5972   int nbOfCells=getNumberOfCells();
5973   int *connI=_nodal_connec_index->getPointer();
5974   int newConnLgth=0;
5975   for(int i=0;i<nbOfCells;i++,connI++)
5976     {
5977       int offset=descIndex[i];
5978       int nbOfEdges=descIndex[i+1]-offset;
5979       //
5980       bool ddirect=desc[offset+nbOfEdges-1]>0;
5981       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5982       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5983       for(int j=0;j<nbOfEdges;j++)
5984         {
5985           bool direct=desc[offset+j]>0;
5986           int edgeId=std::abs(desc[offset+j])-1;
5987           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5988             {
5989               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5990               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5991               int ref2=direct?id1:id2;
5992               if(ref==ref2)
5993                 {
5994                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5995                   newConnLgth+=nbOfSubNodes-1;
5996                   ref=direct?id2:id1;
5997                 }
5998               else
5999                 {
6000                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
6001                   throw INTERP_KERNEL::Exception(oss.str());
6002                 }
6003             }
6004           else
6005             {
6006               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
6007             }
6008         }
6009       newConnLgth++;//+1 is for cell type
6010       connI[1]=newConnLgth;
6011     }
6012   //
6013   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
6014   newConn->alloc(newConnLgth,1);
6015   int *work=newConn->getPointer();
6016   for(int i=0;i<nbOfCells;i++)
6017     {
6018       *work++=INTERP_KERNEL::NORM_POLYGON;
6019       int offset=descIndex[i];
6020       int nbOfEdges=descIndex[i+1]-offset;
6021       for(int j=0;j<nbOfEdges;j++)
6022         {
6023           bool direct=desc[offset+j]>0;
6024           int edgeId=std::abs(desc[offset+j])-1;
6025           if(direct)
6026             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6027           else
6028             {
6029               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6030               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6031               work=std::copy(it,it+nbOfSubNodes-1,work);
6032             }
6033         }
6034     }
6035   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6036   _types.clear();
6037   if(nbOfCells>0)
6038     _types.insert(INTERP_KERNEL::NORM_POLYGON);
6039 }
6040
6041 /*!
6042  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6043  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6044  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6045  * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6046  * so it can be useful to call mergeNodes() before calling this method.
6047  *  \throw If \a this->getMeshDimension() <= 1.
6048  *  \throw If the coordinates array is not set.
6049  *  \throw If the nodal connectivity of cells is not defined.
6050  */
6051 void MEDCouplingUMesh::convertDegeneratedCells()
6052 {
6053   checkFullyDefined();
6054   if(getMeshDimension()<=1)
6055     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6056   int nbOfCells=getNumberOfCells();
6057   if(nbOfCells<1)
6058     return ;
6059   int initMeshLgth=getNodalConnectivityArrayLen();
6060   int *conn=_nodal_connec->getPointer();
6061   int *index=_nodal_connec_index->getPointer();
6062   int posOfCurCell=0;
6063   int newPos=0;
6064   int lgthOfCurCell;
6065   for(int i=0;i<nbOfCells;i++)
6066     {
6067       lgthOfCurCell=index[i+1]-posOfCurCell;
6068       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6069       int newLgth;
6070       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6071                                                                                                      conn+newPos+1,newLgth);
6072       conn[newPos]=newType;
6073       newPos+=newLgth+1;
6074       posOfCurCell=index[i+1];
6075       index[i+1]=newPos;
6076     }
6077   if(newPos!=initMeshLgth)
6078     _nodal_connec->reAlloc(newPos);
6079   computeTypes();
6080 }
6081
6082 /*!
6083  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6084  * A cell is considered to be oriented correctly if an angle between its
6085  * normal vector and a given vector is less than \c PI / \c 2.
6086  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6087  *         cells. 
6088  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6089  *         checked.
6090  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6091  *         is not cleared before filling in.
6092  *  \throw If \a this->getMeshDimension() != 2.
6093  *  \throw If \a this->getSpaceDimension() != 3.
6094  *
6095  *  \if ENABLE_EXAMPLES
6096  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6097  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6098  *  \endif
6099  */
6100 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6101 {
6102   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6103     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6104   int nbOfCells=getNumberOfCells();
6105   const int *conn=_nodal_connec->getConstPointer();
6106   const int *connI=_nodal_connec_index->getConstPointer();
6107   const double *coordsPtr=_coords->getConstPointer();
6108   for(int i=0;i<nbOfCells;i++)
6109     {
6110       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6111       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6112         {
6113           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6114           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6115             cells.push_back(i);
6116         }
6117     }
6118 }
6119
6120 /*!
6121  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6122  * considered to be oriented correctly if an angle between its normal vector and a
6123  * given vector is less than \c PI / \c 2. 
6124  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6125  *         cells. 
6126  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6127  *         checked.
6128  *  \throw If \a this->getMeshDimension() != 2.
6129  *  \throw If \a this->getSpaceDimension() != 3.
6130  *
6131  *  \if ENABLE_EXAMPLES
6132  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6133  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6134  *  \endif
6135  *
6136  *  \sa changeOrientationOfCells
6137  */
6138 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6139 {
6140   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6141     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6142   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6143   const int *connI(_nodal_connec_index->getConstPointer());
6144   const double *coordsPtr(_coords->getConstPointer());
6145   bool isModified(false);
6146   for(int i=0;i<nbOfCells;i++)
6147     {
6148       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6149       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6150         {
6151           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6152           bool isQuadratic(cm.isQuadratic());
6153           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6154             {
6155               isModified=true;
6156               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6157             }
6158         }
6159     }
6160   if(isModified)
6161     _nodal_connec->declareAsNew();
6162   updateTime();
6163 }
6164
6165 /*!
6166  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6167  *
6168  * \sa orientCorrectly2DCells
6169  */
6170 void MEDCouplingUMesh::changeOrientationOfCells()
6171 {
6172   int mdim(getMeshDimension());
6173   if(mdim!=2 && mdim!=1)
6174     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6175   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6176   const int *connI(_nodal_connec_index->getConstPointer());
6177   if(mdim==2)
6178     {//2D
6179       for(int i=0;i<nbOfCells;i++)
6180         {
6181           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6182           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6183           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6184         }
6185     }
6186   else
6187     {//1D
6188       for(int i=0;i<nbOfCells;i++)
6189         {
6190           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6191           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6192           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6193         }
6194     }
6195 }
6196
6197 /*!
6198  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6199  * oriented facets. The normal vector of the facet should point out of the cell.
6200  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6201  *         is not cleared before filling in.
6202  *  \throw If \a this->getMeshDimension() != 3.
6203  *  \throw If \a this->getSpaceDimension() != 3.
6204  *  \throw If the coordinates array is not set.
6205  *  \throw If the nodal connectivity of cells is not defined.
6206  *
6207  *  \if ENABLE_EXAMPLES
6208  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6209  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6210  *  \endif
6211  */
6212 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6213 {
6214   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6215     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6216   int nbOfCells=getNumberOfCells();
6217   const int *conn=_nodal_connec->getConstPointer();
6218   const int *connI=_nodal_connec_index->getConstPointer();
6219   const double *coordsPtr=_coords->getConstPointer();
6220   for(int i=0;i<nbOfCells;i++)
6221     {
6222       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6223       if(type==INTERP_KERNEL::NORM_POLYHED)
6224         {
6225           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6226             cells.push_back(i);
6227         }
6228     }
6229 }
6230
6231 /*!
6232  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6233  * out of the cell. 
6234  *  \throw If \a this->getMeshDimension() != 3.
6235  *  \throw If \a this->getSpaceDimension() != 3.
6236  *  \throw If the coordinates array is not set.
6237  *  \throw If the nodal connectivity of cells is not defined.
6238  *  \throw If the reparation fails.
6239  *
6240  *  \if ENABLE_EXAMPLES
6241  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6242  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6243  *  \endif
6244  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6245  */
6246 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6247 {
6248   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6249     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6250   int nbOfCells=getNumberOfCells();
6251   int *conn=_nodal_connec->getPointer();
6252   const int *connI=_nodal_connec_index->getConstPointer();
6253   const double *coordsPtr=_coords->getConstPointer();
6254   for(int i=0;i<nbOfCells;i++)
6255     {
6256       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6257       if(type==INTERP_KERNEL::NORM_POLYHED)
6258         {
6259           try
6260           {
6261               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6262                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6263           }
6264           catch(INTERP_KERNEL::Exception& e)
6265           {
6266               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6267               throw INTERP_KERNEL::Exception(oss.str());
6268           }
6269         }
6270     }
6271   updateTime();
6272 }
6273
6274 /*!
6275  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6276  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6277  * according to which the first facet of the cell should be oriented to have the normal vector
6278  * pointing out of cell.
6279  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6280  *         cells. The caller is to delete this array using decrRef() as it is no more
6281  *         needed. 
6282  *  \throw If \a this->getMeshDimension() != 3.
6283  *  \throw If \a this->getSpaceDimension() != 3.
6284  *  \throw If the coordinates array is not set.
6285  *  \throw If the nodal connectivity of cells is not defined.
6286  *
6287  *  \if ENABLE_EXAMPLES
6288  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6289  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6290  *  \endif
6291  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6292  */
6293 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6294 {
6295   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6296   if(getMeshDimension()!=3)
6297     throw INTERP_KERNEL::Exception(msg);
6298   int spaceDim=getSpaceDimension();
6299   if(spaceDim!=3)
6300     throw INTERP_KERNEL::Exception(msg);
6301   //
6302   int nbOfCells=getNumberOfCells();
6303   int *conn=_nodal_connec->getPointer();
6304   const int *connI=_nodal_connec_index->getConstPointer();
6305   const double *coo=getCoords()->getConstPointer();
6306   MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6307   for(int i=0;i<nbOfCells;i++)
6308     {
6309       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6310       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6311         {
6312           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6313             {
6314               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6315               cells->pushBackSilent(i);
6316             }
6317         }
6318     }
6319   return cells.retn();
6320 }
6321
6322 /*!
6323  * This method is a faster method to correct orientation of all 3D cells in \a this.
6324  * This method works only if \a this is a 3D mesh, that is to say a mesh with mesh dimension 3 and a space dimension 3.
6325  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6326  * 
6327  * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6328  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, 
6329  */
6330 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6331 {
6332   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6333     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6334   int nbOfCells=getNumberOfCells();
6335   int *conn=_nodal_connec->getPointer();
6336   const int *connI=_nodal_connec_index->getConstPointer();
6337   const double *coordsPtr=_coords->getConstPointer();
6338   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6339   for(int i=0;i<nbOfCells;i++)
6340     {
6341       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6342       switch(type)
6343       {
6344         case INTERP_KERNEL::NORM_TETRA4:
6345           {
6346             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6347               {
6348                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6349                 ret->pushBackSilent(i);
6350               }
6351             break;
6352           }
6353         case INTERP_KERNEL::NORM_PYRA5:
6354           {
6355             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6356               {
6357                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6358                 ret->pushBackSilent(i);
6359               }
6360             break;
6361           }
6362         case INTERP_KERNEL::NORM_PENTA6:
6363         case INTERP_KERNEL::NORM_HEXA8:
6364         case INTERP_KERNEL::NORM_HEXGP12:
6365           {
6366             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6367               {
6368                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6369                 ret->pushBackSilent(i);
6370               }
6371             break;
6372           }
6373         case INTERP_KERNEL::NORM_POLYHED:
6374           {
6375             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6376               {
6377                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6378                 ret->pushBackSilent(i);
6379               }
6380             break;
6381           }
6382         default:
6383           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orientCorrectly3DCells : Your mesh contains type of cell not supported yet ! send mail to anthony.geay@cea.fr to add it !");
6384       }
6385     }
6386   updateTime();
6387   return ret.retn();
6388 }
6389
6390 /*!
6391  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6392  * If it is not the case an exception will be thrown.
6393  * This method is fast because the first cell of \a this is used to compute the plane.
6394  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6395  * \param pos output of size at least 3 used to store a point owned of searched plane.
6396  */
6397 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6398 {
6399   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6400     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6401   const int *conn=_nodal_connec->getConstPointer();
6402   const int *connI=_nodal_connec_index->getConstPointer();
6403   const double *coordsPtr=_coords->getConstPointer();
6404   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6405   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6406 }
6407
6408 /*!
6409  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6410  * cells. Currently cells of the following types are treated:
6411  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6412  * For a cell of other type an exception is thrown.
6413  * Space dimension of a 2D mesh can be either 2 or 3.
6414  * The Edge Ratio of a cell \f$t\f$ is: 
6415  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
6416  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6417  *  the smallest edge lengths of \f$t\f$.
6418  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6419  *          cells and one time, lying on \a this mesh. The caller is to delete this
6420  *          field using decrRef() as it is no more needed. 
6421  *  \throw If the coordinates array is not set.
6422  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6423  *  \throw If the connectivity data array has more than one component.
6424  *  \throw If the connectivity data array has a named component.
6425  *  \throw If the connectivity index data array has more than one component.
6426  *  \throw If the connectivity index data array has a named component.
6427  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6428  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6429  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6430  */
6431 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6432 {
6433   checkConsistencyLight();
6434   int spaceDim=getSpaceDimension();
6435   int meshDim=getMeshDimension();
6436   if(spaceDim!=2 && spaceDim!=3)
6437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6438   if(meshDim!=2 && meshDim!=3)
6439     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6440   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6441   ret->setMesh(this);
6442   int nbOfCells=getNumberOfCells();
6443   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6444   arr->alloc(nbOfCells,1);
6445   double *pt=arr->getPointer();
6446   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6447   const int *conn=_nodal_connec->getConstPointer();
6448   const int *connI=_nodal_connec_index->getConstPointer();
6449   const double *coo=_coords->getConstPointer();
6450   double tmp[12];
6451   for(int i=0;i<nbOfCells;i++,pt++)
6452     {
6453       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6454       switch(t)
6455       {
6456         case INTERP_KERNEL::NORM_TRI3:
6457           {
6458             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6459             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6460             break;
6461           }
6462         case INTERP_KERNEL::NORM_QUAD4:
6463           {
6464             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6465             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6466             break;
6467           }
6468         case INTERP_KERNEL::NORM_TETRA4:
6469           {
6470             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6471             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6472             break;
6473           }
6474         default:
6475           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6476       }
6477       conn+=connI[i+1]-connI[i];
6478     }
6479   ret->setName("EdgeRatio");
6480   ret->synchronizeTimeWithSupport();
6481   return ret.retn();
6482 }
6483
6484 /*!
6485  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6486  * cells. Currently cells of the following types are treated:
6487  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6488  * For a cell of other type an exception is thrown.
6489  * Space dimension of a 2D mesh can be either 2 or 3.
6490  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6491  *          cells and one time, lying on \a this mesh. The caller is to delete this
6492  *          field using decrRef() as it is no more needed. 
6493  *  \throw If the coordinates array is not set.
6494  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6495  *  \throw If the connectivity data array has more than one component.
6496  *  \throw If the connectivity data array has a named component.
6497  *  \throw If the connectivity index data array has more than one component.
6498  *  \throw If the connectivity index data array has a named component.
6499  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6500  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6501  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6502  */
6503 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6504 {
6505   checkConsistencyLight();
6506   int spaceDim=getSpaceDimension();
6507   int meshDim=getMeshDimension();
6508   if(spaceDim!=2 && spaceDim!=3)
6509     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6510   if(meshDim!=2 && meshDim!=3)
6511     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6512   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6513   ret->setMesh(this);
6514   int nbOfCells=getNumberOfCells();
6515   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6516   arr->alloc(nbOfCells,1);
6517   double *pt=arr->getPointer();
6518   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6519   const int *conn=_nodal_connec->getConstPointer();
6520   const int *connI=_nodal_connec_index->getConstPointer();
6521   const double *coo=_coords->getConstPointer();
6522   double tmp[12];
6523   for(int i=0;i<nbOfCells;i++,pt++)
6524     {
6525       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6526       switch(t)
6527       {
6528         case INTERP_KERNEL::NORM_TRI3:
6529           {
6530             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6531             *pt=INTERP_KERNEL::triAspectRatio(tmp);
6532             break;
6533           }
6534         case INTERP_KERNEL::NORM_QUAD4:
6535           {
6536             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6537             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6538             break;
6539           }
6540         case INTERP_KERNEL::NORM_TETRA4:
6541           {
6542             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6543             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6544             break;
6545           }
6546         default:
6547           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6548       }
6549       conn+=connI[i+1]-connI[i];
6550     }
6551   ret->setName("AspectRatio");
6552   ret->synchronizeTimeWithSupport();
6553   return ret.retn();
6554 }
6555
6556 /*!
6557  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6558  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6559  * in 3D space. Currently only cells of the following types are
6560  * treated: INTERP_KERNEL::NORM_QUAD4.
6561  * For a cell of other type an exception is thrown.
6562  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6563  * Defining
6564  * \f$t=\vec{da}\times\vec{ab}\f$,
6565  * \f$u=\vec{ab}\times\vec{bc}\f$
6566  * \f$v=\vec{bc}\times\vec{cd}\f$
6567  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6568  *  \f[
6569  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6570  *  \f]
6571  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6572  *          cells and one time, lying on \a this mesh. The caller is to delete this
6573  *          field using decrRef() as it is no more needed. 
6574  *  \throw If the coordinates array is not set.
6575  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6576  *  \throw If the connectivity data array has more than one component.
6577  *  \throw If the connectivity data array has a named component.
6578  *  \throw If the connectivity index data array has more than one component.
6579  *  \throw If the connectivity index data array has a named component.
6580  *  \throw If \a this->getMeshDimension() != 2.
6581  *  \throw If \a this->getSpaceDimension() != 3.
6582  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6583  */
6584 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6585 {
6586   checkConsistencyLight();
6587   int spaceDim=getSpaceDimension();
6588   int meshDim=getMeshDimension();
6589   if(spaceDim!=3)
6590     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6591   if(meshDim!=2)
6592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6593   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6594   ret->setMesh(this);
6595   int nbOfCells=getNumberOfCells();
6596   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6597   arr->alloc(nbOfCells,1);
6598   double *pt=arr->getPointer();
6599   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6600   const int *conn=_nodal_connec->getConstPointer();
6601   const int *connI=_nodal_connec_index->getConstPointer();
6602   const double *coo=_coords->getConstPointer();
6603   double tmp[12];
6604   for(int i=0;i<nbOfCells;i++,pt++)
6605     {
6606       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6607       switch(t)
6608       {
6609         case INTERP_KERNEL::NORM_QUAD4:
6610           {
6611             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6612             *pt=INTERP_KERNEL::quadWarp(tmp);
6613             break;
6614           }
6615         default:
6616           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6617       }
6618       conn+=connI[i+1]-connI[i];
6619     }
6620   ret->setName("Warp");
6621   ret->synchronizeTimeWithSupport();
6622   return ret.retn();
6623 }
6624
6625
6626 /*!
6627  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6628  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6629  * treated: INTERP_KERNEL::NORM_QUAD4.
6630  * The skew is computed as follow for a quad with points (a,b,c,d): let
6631  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6632  * then the skew is computed as:
6633  *  \f[
6634  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6635  *  \f]
6636  *
6637  * For a cell of other type an exception is thrown.
6638  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6639  *          cells and one time, lying on \a this mesh. The caller is to delete this
6640  *          field using decrRef() as it is no more needed. 
6641  *  \throw If the coordinates array is not set.
6642  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6643  *  \throw If the connectivity data array has more than one component.
6644  *  \throw If the connectivity data array has a named component.
6645  *  \throw If the connectivity index data array has more than one component.
6646  *  \throw If the connectivity index data array has a named component.
6647  *  \throw If \a this->getMeshDimension() != 2.
6648  *  \throw If \a this->getSpaceDimension() != 3.
6649  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6650  */
6651 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6652 {
6653   checkConsistencyLight();
6654   int spaceDim=getSpaceDimension();
6655   int meshDim=getMeshDimension();
6656   if(spaceDim!=3)
6657     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6658   if(meshDim!=2)
6659     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6660   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6661   ret->setMesh(this);
6662   int nbOfCells=getNumberOfCells();
6663   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6664   arr->alloc(nbOfCells,1);
6665   double *pt=arr->getPointer();
6666   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6667   const int *conn=_nodal_connec->getConstPointer();
6668   const int *connI=_nodal_connec_index->getConstPointer();
6669   const double *coo=_coords->getConstPointer();
6670   double tmp[12];
6671   for(int i=0;i<nbOfCells;i++,pt++)
6672     {
6673       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6674       switch(t)
6675       {
6676         case INTERP_KERNEL::NORM_QUAD4:
6677           {
6678             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6679             *pt=INTERP_KERNEL::quadSkew(tmp);
6680             break;
6681           }
6682         default:
6683           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6684       }
6685       conn+=connI[i+1]-connI[i];
6686     }
6687   ret->setName("Skew");
6688   ret->synchronizeTimeWithSupport();
6689   return ret.retn();
6690 }
6691
6692 /*!
6693  * Returns the cell field giving for each cell in \a this its diameter. Diameter means the max length of all possible SEG2 in the cell.
6694  *
6695  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6696  *
6697  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6698  */
6699 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6700 {
6701   checkConsistencyLight();
6702   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6703   ret->setMesh(this);
6704   std::set<INTERP_KERNEL::NormalizedCellType> types;
6705   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6706   int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6707   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6708   arr->alloc(nbCells,1);
6709   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6710     {
6711       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6712       MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6713       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6714     }
6715   ret->setArray(arr);
6716   ret->setName("Diameter");
6717   return ret.retn();
6718 }
6719
6720 /*!
6721  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
6722  * 
6723  * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
6724  *                         For all other cases this input parameter is ignored.
6725  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6726  * 
6727  * \throw If \a this is not fully set (coordinates and connectivity).
6728  * \throw If a cell in \a this has no valid nodeId.
6729  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6730  */
6731 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6732 {
6733   int mDim(getMeshDimension()),sDim(getSpaceDimension());
6734   if((mDim==3 && sDim==3) || (mDim==2 && sDim==3) || (mDim==1 && sDim==1) || ( mDim==1 && sDim==3))  // Compute refined boundary box for quadratic elements only in 2D.
6735     return getBoundingBoxForBBTreeFast();
6736   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6737     {
6738       bool presenceOfQuadratic(false);
6739       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6740         {
6741           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6742           if(cm.isQuadratic())
6743             presenceOfQuadratic=true;
6744         }
6745       if(!presenceOfQuadratic)
6746         return getBoundingBoxForBBTreeFast();
6747       if(mDim==2 && sDim==2)
6748         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6749       else
6750         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6751     }
6752   throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getBoundingBoxForBBTree : Managed dimensions are (mDim=1,sDim=1), (mDim=1,sDim=2), (mDim=1,sDim=3), (mDim=2,sDim=2), (mDim=2,sDim=3) and (mDim=3,sDim=3) !");
6753 }
6754
6755 /*!
6756  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6757  * So meshes having quadratic cells the computed bounding boxes can be invalid !
6758  * 
6759  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6760  * 
6761  * \throw If \a this is not fully set (coordinates and connectivity).
6762  * \throw If a cell in \a this has no valid nodeId.
6763  */
6764 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6765 {
6766   checkFullyDefined();
6767   int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6768   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6769   double *bbox(ret->getPointer());
6770   for(int i=0;i<nbOfCells*spaceDim;i++)
6771     {
6772       bbox[2*i]=std::numeric_limits<double>::max();
6773       bbox[2*i+1]=-std::numeric_limits<double>::max();
6774     }
6775   const double *coordsPtr(_coords->getConstPointer());
6776   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6777   for(int i=0;i<nbOfCells;i++)
6778     {
6779       int offset=connI[i]+1;
6780       int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6781       for(int j=0;j<nbOfNodesForCell;j++)
6782         {
6783           int nodeId=conn[offset+j];
6784           if(nodeId>=0 && nodeId<nbOfNodes)
6785             {
6786               for(int k=0;k<spaceDim;k++)
6787                 {
6788                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6789                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6790                 }
6791               kk++;
6792             }
6793         }
6794       if(kk==0)
6795         {
6796           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6797           throw INTERP_KERNEL::Exception(oss.str());
6798         }
6799     }
6800   return ret.retn();
6801 }
6802
6803 /*!
6804  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6805  * useful for 2D meshes having quadratic cells
6806  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6807  * the two extremities of the arc of circle).
6808  * 
6809  * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
6810  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6811  * \throw If \a this is not fully defined.
6812  * \throw If \a this is not a mesh with meshDimension equal to 2.
6813  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6814  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6815  */
6816 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6817 {
6818   checkFullyDefined();
6819   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6820   if(spaceDim!=2 || mDim!=2)
6821     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic : This method should be applied on mesh with mesh dimension equal to 2 and space dimension also equal to 2!");
6822   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6823   double *bbox(ret->getPointer());
6824   const double *coords(_coords->getConstPointer());
6825   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6826   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6827     {
6828       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6829       int sz(connI[1]-connI[0]-1);
6830       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6831       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6832       INTERP_KERNEL::QuadraticPolygon *pol(0);
6833       for(int j=0;j<sz;j++)
6834         {
6835           int nodeId(conn[*connI+1+j]);
6836           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6837         }
6838       if(!cm.isQuadratic())
6839         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6840       else
6841         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6842       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6843       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); 
6844     }
6845   return ret.retn();
6846 }
6847
6848 /*!
6849  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6850  * useful for 2D meshes having quadratic cells
6851  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6852  * the two extremities of the arc of circle).
6853  * 
6854  * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
6855  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6856  * \throw If \a this is not fully defined.
6857  * \throw If \a this is not a mesh with meshDimension equal to 1.
6858  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6859  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6860  */
6861 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6862 {
6863   checkFullyDefined();
6864   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6865   if(spaceDim!=2 || mDim!=1)
6866     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic : This method should be applied on mesh with mesh dimension equal to 1 and space dimension also equal to 2!");
6867   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6868   double *bbox(ret->getPointer());
6869   const double *coords(_coords->getConstPointer());
6870   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6871   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6872     {
6873       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6874       int sz(connI[1]-connI[0]-1);
6875       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6876       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6877       INTERP_KERNEL::Edge *edge(0);
6878       for(int j=0;j<sz;j++)
6879         {
6880           int nodeId(conn[*connI+1+j]);
6881           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6882         }
6883       if(!cm.isQuadratic())
6884         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6885       else
6886         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6887       const INTERP_KERNEL::Bounds& b(edge->getBounds());
6888       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6889     }
6890   return ret.retn();
6891 }
6892
6893 /// @cond INTERNAL
6894
6895 namespace MEDCouplingImpl
6896 {
6897   class ConnReader
6898   {
6899   public:
6900     ConnReader(const int *c, int val):_conn(c),_val(val) { }
6901     bool operator() (const int& pos) { return _conn[pos]!=_val; }
6902   private:
6903     const int *_conn;
6904     int _val;
6905   };
6906
6907   class ConnReader2
6908   {
6909   public:
6910     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6911     bool operator() (const int& pos) { return _conn[pos]==_val; }
6912   private:
6913     const int *_conn;
6914     int _val;
6915   };
6916 }
6917
6918 /// @endcond
6919
6920 /*!
6921  * This method expects that \a this is sorted by types. If not an exception will be thrown.
6922  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6923  * \a this is composed in cell types.
6924  * The returned array is of size 3*n where n is the number of different types present in \a this. 
6925  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here. 
6926  * This parameter is kept only for compatibility with other methode listed above.
6927  */
6928 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6929 {
6930   checkConnectivityFullyDefined();
6931   const int *conn=_nodal_connec->getConstPointer();
6932   const int *connI=_nodal_connec_index->getConstPointer();
6933   const int *work=connI;
6934   int nbOfCells=getNumberOfCells();
6935   std::size_t n=getAllGeoTypes().size();
6936   std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6937   std::set<INTERP_KERNEL::NormalizedCellType> types;
6938   for(std::size_t i=0;work!=connI+nbOfCells;i++)
6939     {
6940       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6941       if(types.find(typ)!=types.end())
6942         {
6943           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6944           oss << " is not contiguous !";
6945           throw INTERP_KERNEL::Exception(oss.str());
6946         }
6947       types.insert(typ);
6948       ret[3*i]=typ;
6949       const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6950       ret[3*i+1]=(int)std::distance(work,work2);
6951       work=work2;
6952     }
6953   return ret;
6954 }
6955
6956 /*!
6957  * This method is used to check that this has contiguous cell type in same order than described in \a code.
6958  * only for types cell, type node is not managed.
6959  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6960  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6961  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6962  * If 2 or more same geometric type is in \a code and exception is thrown too.
6963  *
6964  * This method firstly checks
6965  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6966  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6967  * an exception is thrown too.
6968  * 
6969  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6970  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown 
6971  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6972  */
6973 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6974 {
6975   if(code.empty())
6976     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6977   std::size_t sz=code.size();
6978   std::size_t n=sz/3;
6979   if(sz%3!=0)
6980     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6981   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6982   int nb=0;
6983   bool isNoPflUsed=true;
6984   for(std::size_t i=0;i<n;i++)
6985     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6986       {
6987         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6988         nb+=code[3*i+1];
6989         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6990           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6991         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6992       }
6993   if(types.size()!=n)
6994     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6995   if(isNoPflUsed)
6996     {
6997       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6998         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6999       if(types.size()==_types.size())
7000         return 0;
7001     }
7002   MCAuto<DataArrayInt> ret=DataArrayInt::New();
7003   ret->alloc(nb,1);
7004   int *retPtr=ret->getPointer();
7005   const int *connI=_nodal_connec_index->getConstPointer();
7006   const int *conn=_nodal_connec->getConstPointer();
7007   int nbOfCells=getNumberOfCells();
7008   const int *i=connI;
7009   int kk=0;
7010   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
7011     {
7012       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
7013       int offset=(int)std::distance(connI,i);
7014       const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
7015       int nbOfCellsOfCurType=(int)std::distance(i,j);
7016       if(code[3*kk+2]==-1)
7017         for(int k=0;k<nbOfCellsOfCurType;k++)
7018           *retPtr++=k+offset;
7019       else
7020         {
7021           int idInIdsPerType=code[3*kk+2];
7022           if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
7023             {
7024               const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
7025               if(zePfl)
7026                 {
7027                   zePfl->checkAllocated();
7028                   if(zePfl->getNumberOfComponents()==1)
7029                     {
7030                       for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7031                         {
7032                           if(*k>=0 && *k<nbOfCellsOfCurType)
7033                             *retPtr=(*k)+offset;
7034                           else
7035                             {
7036                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7037                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7038                               throw INTERP_KERNEL::Exception(oss.str());
7039                             }
7040                         }
7041                     }
7042                   else
7043                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7044                 }
7045               else
7046                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7047             }
7048           else
7049             {
7050               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7051               oss << " should be in [0," << idsPerType.size() << ") !";
7052               throw INTERP_KERNEL::Exception(oss.str());
7053             }
7054         }
7055       i=j;
7056     }
7057   return ret.retn();
7058 }
7059
7060 /*!
7061  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7062  * This method is the opposite of MEDCouplingUMesh::checkTypeConsistencyAndContig method. Given a list of cells in \a profile it returns a list of sub-profiles sorted by geo type.
7063  * The result is put in the array \a idsPerType. In the returned parameter \a code, foreach i \a code[3*i+2] refers (if different from -1) to a location into the \a idsPerType.
7064  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7065  * 
7066  * \param [in] profile
7067  * \param [out] code is a vector of size 3*n where n is the number of different geometric type in \a this \b reduced to the profile \a profile. \a code has exactly the same semantic than in MEDCouplingUMesh::checkTypeConsistencyAndContig method.
7068  * \param [out] idsInPflPerType is a vector of size of different geometric type in the subpart defined by \a profile of \a this ( equal to \a code.size()/3). For each i,
7069  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7070  * \param [out] idsPerType is a vector of size of different sub profiles needed to be defined to represent the profile \a profile for a given geometric type.
7071  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7072  * \throw if \a profile has not exactly one component. It throws too, if \a profile contains some values not in [0,getNumberOfCells()) or if \a this is not fully defined
7073  */
7074 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7075 {
7076   if(!profile)
7077     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7078   if(profile->getNumberOfComponents()!=1)
7079     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7080   checkConnectivityFullyDefined();
7081   const int *conn=_nodal_connec->getConstPointer();
7082   const int *connI=_nodal_connec_index->getConstPointer();
7083   int nbOfCells=getNumberOfCells();
7084   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7085   std::vector<int> typeRangeVals(1);
7086   for(const int *i=connI;i!=connI+nbOfCells;)
7087     {
7088       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7089       if(std::find(types.begin(),types.end(),curType)!=types.end())
7090         {
7091           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7092         }
7093       types.push_back(curType);
7094       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7095       typeRangeVals.push_back((int)std::distance(connI,i));
7096     }
7097   //
7098   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7099   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7100   MCAuto<DataArrayInt> tmp0=castArr;
7101   MCAuto<DataArrayInt> tmp1=rankInsideCast;
7102   MCAuto<DataArrayInt> tmp2=castsPresent;
7103   //
7104   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7105   code.resize(3*nbOfCastsFinal);
7106   std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7107   std::vector< MCAuto<DataArrayInt> > idsPerType2;
7108   for(int i=0;i<nbOfCastsFinal;i++)
7109     {
7110       int castId=castsPresent->getIJ(i,0);
7111       MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7112       idsInPflPerType2.push_back(tmp3);
7113       code[3*i]=(int)types[castId];
7114       code[3*i+1]=tmp3->getNumberOfTuples();
7115       MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7116       if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7117         {
7118           tmp4->copyStringInfoFrom(*profile);
7119           idsPerType2.push_back(tmp4);
7120           code[3*i+2]=(int)idsPerType2.size()-1;
7121         }
7122       else
7123         {
7124           code[3*i+2]=-1;
7125         }
7126     }
7127   std::size_t sz2=idsInPflPerType2.size();
7128   idsInPflPerType.resize(sz2);
7129   for(std::size_t i=0;i<sz2;i++)
7130     {
7131       DataArrayInt *locDa=idsInPflPerType2[i];
7132       locDa->incrRef();
7133       idsInPflPerType[i]=locDa;
7134     }
7135   std::size_t sz=idsPerType2.size();
7136   idsPerType.resize(sz);
7137   for(std::size_t i=0;i<sz;i++)
7138     {
7139       DataArrayInt *locDa=idsPerType2[i];
7140       locDa->incrRef();
7141       idsPerType[i]=locDa;
7142     }
7143 }
7144
7145 /*!
7146  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7147  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7148  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7149  * This method returns 5+2 elements. 'desc', 'descIndx', 'revDesc', 'revDescIndx' and 'meshnM1' behaves exactly as MEDCoupling::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.
7150  */
7151 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7152 {
7153   checkFullyDefined();
7154   nM1LevMesh->checkFullyDefined();
7155   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7156     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7157   if(_coords!=nM1LevMesh->getCoords())
7158     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7159   MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7160   MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7161   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7162   MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7163   desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7164   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7165   tmp->setConnectivity(tmp0,tmp1);
7166   tmp->renumberCells(ret0->getConstPointer(),false);
7167   revDesc=tmp->getNodalConnectivity();
7168   revDescIndx=tmp->getNodalConnectivityIndex();
7169   DataArrayInt *ret=0;
7170   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7171     {
7172       int tmp2;
7173       ret->getMaxValue(tmp2);
7174       ret->decrRef();
7175       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7176       throw INTERP_KERNEL::Exception(oss.str());
7177     }
7178   nM1LevMeshIds=ret;
7179   //
7180   revDesc->incrRef();
7181   revDescIndx->incrRef();
7182   ret1->incrRef();
7183   ret0->incrRef();
7184   meshnM1Old2New=ret0;
7185   return ret1;
7186 }
7187
7188 /*!
7189  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7190  * necessary for writing the mesh to MED file. Additionally returns a permutation array
7191  * in "Old to New" mode.
7192  *  \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7193  *          this array using decrRef() as it is no more needed.
7194  *  \throw If the nodal connectivity of cells is not defined.
7195  */
7196 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7197 {
7198   checkConnectivityFullyDefined();
7199   MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7200   renumberCells(ret->getConstPointer(),false);
7201   return ret.retn();
7202 }
7203
7204 /*!
7205  * This methods checks that cells are sorted by their types.
7206  * This method makes asumption (no check) that connectivity is correctly set before calling.
7207  */
7208 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7209 {
7210   checkFullyDefined();
7211   const int *conn=_nodal_connec->getConstPointer();
7212   const int *connI=_nodal_connec_index->getConstPointer();
7213   int nbOfCells=getNumberOfCells();
7214   std::set<INTERP_KERNEL::NormalizedCellType> types;
7215   for(const int *i=connI;i!=connI+nbOfCells;)
7216     {
7217       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7218       if(types.find(curType)!=types.end())
7219         return false;
7220       types.insert(curType);
7221       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7222     }
7223   return true;
7224 }
7225
7226 /*!
7227  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7228  * The geometric type order is specified by MED file.
7229  * 
7230  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7231  */
7232 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7233 {
7234   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7235 }
7236
7237 /*!
7238  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7239  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7240  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7241  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7242  */
7243 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7244 {
7245   checkFullyDefined();
7246   const int *conn=_nodal_connec->getConstPointer();
7247   const int *connI=_nodal_connec_index->getConstPointer();
7248   int nbOfCells=getNumberOfCells();
7249   if(nbOfCells==0)
7250     return true;
7251   int lastPos=-1;
7252   std::set<INTERP_KERNEL::NormalizedCellType> sg;
7253   for(const int *i=connI;i!=connI+nbOfCells;)
7254     {
7255       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7256       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7257       if(isTypeExists!=orderEnd)
7258         {
7259           int pos=(int)std::distance(orderBg,isTypeExists);
7260           if(pos<=lastPos)
7261             return false;
7262           lastPos=pos;
7263           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7264         }
7265       else
7266         {
7267           if(sg.find(curType)==sg.end())
7268             {
7269               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7270               sg.insert(curType);
7271             }
7272           else
7273             return false;
7274         }
7275     }
7276   return true;
7277 }
7278
7279 /*!
7280  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7281  * 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
7282  * 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'.
7283  */
7284 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7285 {
7286   checkConnectivityFullyDefined();
7287   int nbOfCells=getNumberOfCells();
7288   const int *conn=_nodal_connec->getConstPointer();
7289   const int *connI=_nodal_connec_index->getConstPointer();
7290   MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7291   MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7292   tmpa->alloc(nbOfCells,1);
7293   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7294   tmpb->fillWithZero();
7295   int *tmp=tmpa->getPointer();
7296   int *tmp2=tmpb->getPointer();
7297   for(const int *i=connI;i!=connI+nbOfCells;i++)
7298     {
7299       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7300       if(where!=orderEnd)
7301         {
7302           int pos=(int)std::distance(orderBg,where);
7303           tmp2[pos]++;
7304           tmp[std::distance(connI,i)]=pos;
7305         }
7306       else
7307         {
7308           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7309           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7310           oss << " has a type " << cm.getRepr() << " not in input array of type !";
7311           throw INTERP_KERNEL::Exception(oss.str());
7312         }
7313     }
7314   nbPerType=tmpb.retn();
7315   return tmpa.retn();
7316 }
7317
7318 /*!
7319  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7320  *
7321  * \return a new object containing the old to new correspondance.
7322  *
7323  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7324  */
7325 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7326 {
7327   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7328 }
7329
7330 /*!
7331  * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
7332  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7333  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7334  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7335  */
7336 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7337 {
7338   DataArrayInt *nbPerType=0;
7339   MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7340   nbPerType->decrRef();
7341   return tmpa->buildPermArrPerLevel();
7342 }
7343
7344 /*!
7345  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7346  * The number of cells remains unchanged after the call of this method.
7347  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7348  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7349  *
7350  * \return the array giving the correspondance old to new.
7351  */
7352 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7353 {
7354   checkFullyDefined();
7355   computeTypes();
7356   const int *conn=_nodal_connec->getConstPointer();
7357   const int *connI=_nodal_connec_index->getConstPointer();
7358   int nbOfCells=getNumberOfCells();
7359   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7360   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7361     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7362       {
7363         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7364         types.push_back(curType);
7365         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7366       }
7367   DataArrayInt *ret=DataArrayInt::New();
7368   ret->alloc(nbOfCells,1);
7369   int *retPtr=ret->getPointer();
7370   std::fill(retPtr,retPtr+nbOfCells,-1);
7371   int newCellId=0;
7372   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7373     {
7374       for(const int *i=connI;i!=connI+nbOfCells;i++)
7375         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7376           retPtr[std::distance(connI,i)]=newCellId++;
7377     }
7378   renumberCells(retPtr,false);
7379   return ret;
7380 }
7381
7382 /*!
7383  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7384  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7385  * This method makes asumption that connectivity is correctly set before calling.
7386  */
7387 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7388 {
7389   checkConnectivityFullyDefined();
7390   const int *conn=_nodal_connec->getConstPointer();
7391   const int *connI=_nodal_connec_index->getConstPointer();
7392   int nbOfCells=getNumberOfCells();
7393   std::vector<MEDCouplingUMesh *> ret;
7394   for(const int *i=connI;i!=connI+nbOfCells;)
7395     {
7396       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7397       int beginCellId=(int)std::distance(connI,i);
7398       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7399       int endCellId=(int)std::distance(connI,i);
7400       int sz=endCellId-beginCellId;
7401       int *cells=new int[sz];
7402       for(int j=0;j<sz;j++)
7403         cells[j]=beginCellId+j;
7404       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7405       delete [] cells;
7406       ret.push_back(m);
7407     }
7408   return ret;
7409 }
7410
7411 /*!
7412  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7413  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7414  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7415  *
7416  * \return a newly allocated instance, that the caller must manage.
7417  * \throw If \a this contains more than one geometric type.
7418  * \throw If the nodal connectivity of \a this is not fully defined.
7419  * \throw If the internal data is not coherent.
7420  */
7421 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7422 {
7423   checkConnectivityFullyDefined();
7424   if(_types.size()!=1)
7425     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7426   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7427   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7428   ret->setCoords(getCoords());
7429   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7430   if(retC)
7431     {
7432       MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7433       retC->setNodalConnectivity(c);
7434     }
7435   else
7436     {
7437       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7438       if(!retD)
7439         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7440       DataArrayInt *c=0,*ci=0;
7441       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7442       MCAuto<DataArrayInt> cs(c),cis(ci);
7443       retD->setNodalConnectivity(cs,cis);
7444     }
7445   return ret.retn();
7446 }
7447
7448 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7449 {
7450   checkConnectivityFullyDefined();
7451   if(_types.size()!=1)
7452     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7453   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7454   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7455   if(cm.isDynamic())
7456     {
7457       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7458       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7459       throw INTERP_KERNEL::Exception(oss.str());
7460     }
7461   int nbCells=getNumberOfCells();
7462   int typi=(int)typ;
7463   int nbNodesPerCell=(int)cm.getNumberOfNodes();
7464   MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7465   int *outPtr=connOut->getPointer();
7466   const int *conn=_nodal_connec->begin();
7467   const int *connI=_nodal_connec_index->begin();
7468   nbNodesPerCell++;
7469   for(int i=0;i<nbCells;i++,connI++)
7470     {
7471       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7472         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7473       else
7474         {
7475           std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : there something wrong in cell #" << i << " ! The type of cell is not those expected, or the length of nodal connectivity is not those expected (" << nbNodesPerCell-1 << ") !";
7476           throw INTERP_KERNEL::Exception(oss.str());
7477         }
7478     }
7479   return connOut.retn();
7480 }
7481
7482 /*!
7483  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7484  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7485  * \param nodalConn
7486  * \param nodalConnI
7487  */
7488 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7489 {
7490   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7491   checkConnectivityFullyDefined();
7492   if(_types.size()!=1)
7493     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7494   int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7495   if(lgth<nbCells)
7496     throw INTERP_KERNEL::Exception(msg0);
7497   MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7498   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7499   int *cp(c->getPointer()),*cip(ci->getPointer());
7500   const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7501   cip[0]=0;
7502   for(int i=0;i<nbCells;i++,cip++,incip++)
7503     {
7504       int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7505       int delta(stop-strt);
7506       if(delta>=1)
7507         {
7508           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7509             cp=std::copy(incp+strt,incp+stop,cp);
7510           else
7511             throw INTERP_KERNEL::Exception(msg0);
7512         }
7513       else
7514         throw INTERP_KERNEL::Exception(msg0);
7515       cip[1]=cip[0]+delta;
7516     }
7517   nodalConn=c.retn(); nodalConnIndex=ci.retn();
7518 }
7519
7520 /*!
7521  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7522  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7523  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7524  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7525  * are not used here to avoid the build of big permutation array.
7526  *
7527  * \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
7528  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7529  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7530  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7531  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7532  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
7533  * \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
7534  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7535  */
7536 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7537                                                                             DataArrayInt *&szOfCellGrpOfSameType,
7538                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType)
7539 {
7540   std::vector<const MEDCouplingUMesh *> ms2;
7541   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7542     if(*it)
7543       {
7544         (*it)->checkConnectivityFullyDefined();
7545         ms2.push_back(*it);
7546       }
7547   if(ms2.empty())
7548     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7549   const DataArrayDouble *refCoo=ms2[0]->getCoords();
7550   int meshDim=ms2[0]->getMeshDimension();
7551   std::vector<const MEDCouplingUMesh *> m1ssm;
7552   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7553   //
7554   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7555   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7556   int fake=0,rk=0;
7557   MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7558   ret1->alloc(0,1); ret2->alloc(0,1);
7559   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7560     {
7561       if(meshDim!=(*it)->getMeshDimension())
7562         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7563       if(refCoo!=(*it)->getCoords())
7564         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7565       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7566       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7567       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7568       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7569         {
7570           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7571           m1ssmSingleAuto.push_back(singleCell);
7572           m1ssmSingle.push_back(singleCell);
7573           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7574         }
7575     }
7576   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7577   MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7578   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7579   for(std::size_t i=0;i<m1ssm.size();i++)
7580     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7581   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7582   szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7583   idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7584   return ret0.retn();
7585 }
7586
7587 /*!
7588  * This method returns a newly created DataArrayInt instance.
7589  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7590  */
7591 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7592 {
7593   checkFullyDefined();
7594   const int *conn=_nodal_connec->getConstPointer();
7595   const int *connIndex=_nodal_connec_index->getConstPointer();
7596   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7597   for(const int *w=begin;w!=end;w++)
7598     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7599       ret->pushBackSilent(*w);
7600   return ret.retn();
7601 }
7602
7603 /*!
7604  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7605  * are in [0:getNumberOfCells())
7606  */
7607 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7608 {
7609   checkFullyDefined();
7610   const int *conn=_nodal_connec->getConstPointer();
7611   const int *connI=_nodal_connec_index->getConstPointer();
7612   int nbOfCells=getNumberOfCells();
7613   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7614   int *tmp=new int[nbOfCells];
7615   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7616     {
7617       int j=0;
7618       for(const int *i=connI;i!=connI+nbOfCells;i++)
7619         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7620           tmp[std::distance(connI,i)]=j++;
7621     }
7622   DataArrayInt *ret=DataArrayInt::New();
7623   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7624   ret->copyStringInfoFrom(*da);
7625   int *retPtr=ret->getPointer();
7626   const int *daPtr=da->getConstPointer();
7627   int nbOfElems=da->getNbOfElems();
7628   for(int k=0;k<nbOfElems;k++)
7629     retPtr[k]=tmp[daPtr[k]];
7630   delete [] tmp;
7631   return ret;
7632 }
7633
7634 /*!
7635  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7636  * This method \b works \b for mesh sorted by type.
7637  * cells whose ids is in 'idsPerGeoType' array.
7638  * This method conserves coords and name of mesh.
7639  */
7640 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7641 {
7642   std::vector<int> code=getDistributionOfTypes();
7643   std::size_t nOfTypesInThis=code.size()/3;
7644   int sz=0,szOfType=0;
7645   for(std::size_t i=0;i<nOfTypesInThis;i++)
7646     {
7647       if(code[3*i]!=type)
7648         sz+=code[3*i+1];
7649       else
7650         szOfType=code[3*i+1];
7651     }
7652   for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7653     if(*work<0 || *work>=szOfType)
7654       {
7655         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7656         oss << ". It should be in [0," << szOfType << ") !";
7657         throw INTERP_KERNEL::Exception(oss.str());
7658       }
7659   MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7660   int *idsPtr=idsTokeep->getPointer();
7661   int offset=0;
7662   for(std::size_t i=0;i<nOfTypesInThis;i++)
7663     {
7664       if(code[3*i]!=type)
7665         for(int j=0;j<code[3*i+1];j++)
7666           *idsPtr++=offset+j;
7667       else
7668         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7669       offset+=code[3*i+1];
7670     }
7671   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7672   ret->copyTinyInfoFrom(this);
7673   return ret.retn();
7674 }
7675
7676 /*!
7677  * This method returns a vector of size 'this->getNumberOfCells()'.
7678  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7679  */
7680 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7681 {
7682   int ncell=getNumberOfCells();
7683   std::vector<bool> ret(ncell);
7684   const int *cI=getNodalConnectivityIndex()->getConstPointer();
7685   const int *c=getNodalConnectivity()->getConstPointer();
7686   for(int i=0;i<ncell;i++)
7687     {
7688       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7689       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7690       ret[i]=cm.isQuadratic();
7691     }
7692   return ret;
7693 }
7694
7695 /*!
7696  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7697  */
7698 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7699 {
7700   if(other->getType()!=UNSTRUCTURED)
7701     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7702   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7703   return MergeUMeshes(this,otherC);
7704 }
7705
7706 /*!
7707  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7708  * computed by averaging coordinates of cell nodes, so this method is not a right
7709  * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7710  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7711  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7712  *          components. The caller is to delete this array using decrRef() as it is
7713  *          no more needed.
7714  *  \throw If the coordinates array is not set.
7715  *  \throw If the nodal connectivity of cells is not defined.
7716  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7717  */
7718 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7719 {
7720   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7721   int spaceDim=getSpaceDimension();
7722   int nbOfCells=getNumberOfCells();
7723   ret->alloc(nbOfCells,spaceDim);
7724   ret->copyStringInfoFrom(*getCoords());
7725   double *ptToFill=ret->getPointer();
7726   const int *nodal=_nodal_connec->getConstPointer();
7727   const int *nodalI=_nodal_connec_index->getConstPointer();
7728   const double *coor=_coords->getConstPointer();
7729   for(int i=0;i<nbOfCells;i++)
7730     {
7731       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7732       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7733       ptToFill+=spaceDim;
7734     }
7735   return ret.retn();
7736 }
7737
7738 /*!
7739  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7740  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the 
7741  * 
7742  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned 
7743  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7744  * 
7745  * \sa MEDCouplingUMesh::computeCellCenterOfMass
7746  * \throw If \a this is not fully defined (coordinates and connectivity)
7747  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7748  */
7749 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7750 {
7751   checkFullyDefined();
7752   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7753   int spaceDim=getSpaceDimension();
7754   int nbOfCells=getNumberOfCells();
7755   int nbOfNodes=getNumberOfNodes();
7756   ret->alloc(nbOfCells,spaceDim);
7757   double *ptToFill=ret->getPointer();
7758   const int *nodal=_nodal_connec->getConstPointer();
7759   const int *nodalI=_nodal_connec_index->getConstPointer();
7760   const double *coor=_coords->getConstPointer();
7761   for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7762     {
7763       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7764       std::fill(ptToFill,ptToFill+spaceDim,0.);
7765       if(type!=INTERP_KERNEL::NORM_POLYHED)
7766         {
7767           for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7768             {
7769               if(*conn>=0 && *conn<nbOfNodes)
7770                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7771               else
7772                 {
7773                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
7774                   throw INTERP_KERNEL::Exception(oss.str());
7775                 }
7776             }
7777           int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7778           if(nbOfNodesInCell>0)
7779             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7780           else
7781             {
7782               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7783               throw INTERP_KERNEL::Exception(oss.str());
7784             }
7785         }
7786       else
7787         {
7788           std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7789           s.erase(-1);
7790           for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7791             {
7792               if(*it>=0 && *it<nbOfNodes)
7793                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7794               else
7795                 {
7796                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
7797                   throw INTERP_KERNEL::Exception(oss.str());
7798                 }
7799             }
7800           if(!s.empty())
7801             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7802           else
7803             {
7804               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7805               throw INTERP_KERNEL::Exception(oss.str());
7806             }
7807         }
7808     }
7809   return ret.retn();
7810 }
7811
7812 /*!
7813  * Returns a new DataArrayDouble holding barycenters of specified cells. The
7814  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7815  * are specified via an array of cell ids. 
7816  *  \warning Validity of the specified cell ids is not checked! 
7817  *           Valid range is [ 0, \a this->getNumberOfCells() ).
7818  *  \param [in] begin - an array of cell ids of interest.
7819  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7820  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7821  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7822  *          caller is to delete this array using decrRef() as it is no more needed. 
7823  *  \throw If the coordinates array is not set.
7824  *  \throw If the nodal connectivity of cells is not defined.
7825  *
7826  *  \if ENABLE_EXAMPLES
7827  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7828  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7829  *  \endif
7830  */
7831 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7832 {
7833   DataArrayDouble *ret=DataArrayDouble::New();
7834   int spaceDim=getSpaceDimension();
7835   int nbOfTuple=(int)std::distance(begin,end);
7836   ret->alloc(nbOfTuple,spaceDim);
7837   double *ptToFill=ret->getPointer();
7838   double *tmp=new double[spaceDim];
7839   const int *nodal=_nodal_connec->getConstPointer();
7840   const int *nodalI=_nodal_connec_index->getConstPointer();
7841   const double *coor=_coords->getConstPointer();
7842   for(const int *w=begin;w!=end;w++)
7843     {
7844       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7845       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7846       ptToFill+=spaceDim;
7847     }
7848   delete [] tmp;
7849   return ret;
7850 }
7851
7852 /*!
7853  * Returns a DataArrayDouble instance giving for each cell in \a this the equation of plane given by "a*X+b*Y+c*Z+d=0".
7854  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7855  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7856  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7857  * This method is useful to detect 2D cells in 3D space that are not coplanar.
7858  * 
7859  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7860  * \throw If spaceDim!=3 or meshDim!=2.
7861  * \throw If connectivity of \a this is invalid.
7862  * \throw If connectivity of a cell in \a this points to an invalid node.
7863  */
7864 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7865 {
7866   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7867   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7868   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7869     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7870   ret->alloc(nbOfCells,4);
7871   double *retPtr(ret->getPointer());
7872   const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7873   const double *coor(_coords->begin());
7874   for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7875     {
7876       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7877       if(nodalI[1]-nodalI[0]>=3)
7878         {
7879           for(int j=0;j<3;j++)
7880             {
7881               int nodeId(nodal[nodalI[0]+1+j]);
7882               if(nodeId>=0 && nodeId<nbOfNodes)
7883                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7884               else
7885                 {
7886                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7887                   throw INTERP_KERNEL::Exception(oss.str());
7888                 }
7889             }
7890         }
7891       else
7892         {
7893           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7894           throw INTERP_KERNEL::Exception(oss.str());
7895         }
7896       INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7897       retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7898     }
7899   return ret.retn();
7900 }
7901
7902 /*!
7903  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7904  * 
7905  */
7906 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7907 {
7908   if(!da)
7909     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7910   da->checkAllocated();
7911   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7912   ret->setCoords(da);
7913   int nbOfTuples=da->getNumberOfTuples();
7914   MCAuto<DataArrayInt> c=DataArrayInt::New();
7915   MCAuto<DataArrayInt> cI=DataArrayInt::New();
7916   c->alloc(2*nbOfTuples,1);
7917   cI->alloc(nbOfTuples+1,1);
7918   int *cp=c->getPointer();
7919   int *cip=cI->getPointer();
7920   *cip++=0;
7921   for(int i=0;i<nbOfTuples;i++)
7922     {
7923       *cp++=INTERP_KERNEL::NORM_POINT1;
7924       *cp++=i;
7925       *cip++=2*(i+1);
7926     }
7927   ret->setConnectivity(c,cI,true);
7928   return ret.retn();
7929 }
7930 /*!
7931  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7932  * Cells and nodes of
7933  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7934  *  \param [in] mesh1 - the first mesh.
7935  *  \param [in] mesh2 - the second mesh.
7936  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7937  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7938  *          is no more needed.
7939  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7940  *  \throw If the coordinates array is not set in none of the meshes.
7941  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7942  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7943  */
7944 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7945 {
7946   std::vector<const MEDCouplingUMesh *> tmp(2);
7947   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7948   return MergeUMeshes(tmp);
7949 }
7950
7951 /*!
7952  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7953  * Cells and nodes of
7954  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7955  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7956  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7957  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7958  *          is no more needed.
7959  *  \throw If \a a.size() == 0.
7960  *  \throw If \a a[ *i* ] == NULL.
7961  *  \throw If the coordinates array is not set in none of the meshes.
7962  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7963  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7964  */
7965 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7966 {
7967   std::size_t sz=a.size();
7968   if(sz==0)
7969     return MergeUMeshesLL(a);
7970   for(std::size_t ii=0;ii<sz;ii++)
7971     if(!a[ii])
7972       {
7973         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7974         throw INTERP_KERNEL::Exception(oss.str());
7975       }
7976   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7977   std::vector< const MEDCouplingUMesh * > aa(sz);
7978   int spaceDim=-3;
7979   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7980     {
7981       const MEDCouplingUMesh *cur=a[i];
7982       const DataArrayDouble *coo=cur->getCoords();
7983       if(coo)
7984         spaceDim=coo->getNumberOfComponents();
7985     }
7986   if(spaceDim==-3)
7987     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7988   for(std::size_t i=0;i<sz;i++)
7989     {
7990       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7991       aa[i]=bb[i];
7992     }
7993   return MergeUMeshesLL(aa);
7994 }
7995
7996 /// @cond INTERNAL
7997
7998 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(const std::vector<const MEDCouplingUMesh *>& a)
7999 {
8000   if(a.empty())
8001     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
8002   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
8003   int meshDim=(*it)->getMeshDimension();
8004   int nbOfCells=(*it)->getNumberOfCells();
8005   int meshLgth=(*it++)->getNodalConnectivityArrayLen();
8006   for(;it!=a.end();it++)
8007     {
8008       if(meshDim!=(*it)->getMeshDimension())
8009         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
8010       nbOfCells+=(*it)->getNumberOfCells();
8011       meshLgth+=(*it)->getNodalConnectivityArrayLen();
8012     }
8013   std::vector<const MEDCouplingPointSet *> aps(a.size());
8014   std::copy(a.begin(),a.end(),aps.begin());
8015   MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
8016   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
8017   ret->setCoords(pts);
8018   MCAuto<DataArrayInt> c=DataArrayInt::New();
8019   c->alloc(meshLgth,1);
8020   int *cPtr=c->getPointer();
8021   MCAuto<DataArrayInt> cI=DataArrayInt::New();
8022   cI->alloc(nbOfCells+1,1);
8023   int *cIPtr=cI->getPointer();
8024   *cIPtr++=0;
8025   int offset=0;
8026   int offset2=0;
8027   for(it=a.begin();it!=a.end();it++)
8028     {
8029       int curNbOfCell=(*it)->getNumberOfCells();
8030       const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8031       const int *curC=(*it)->_nodal_connec->getConstPointer();
8032       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8033       for(int j=0;j<curNbOfCell;j++)
8034         {
8035           const int *src=curC+curCI[j];
8036           *cPtr++=*src++;
8037           for(;src!=curC+curCI[j+1];src++,cPtr++)
8038             {
8039               if(*src!=-1)
8040                 *cPtr=*src+offset2;
8041               else
8042                 *cPtr=-1;
8043             }
8044         }
8045       offset+=curCI[curNbOfCell];
8046       offset2+=(*it)->getNumberOfNodes();
8047     }
8048   //
8049   ret->setConnectivity(c,cI,true);
8050   return ret.retn();
8051 }
8052
8053 /// @endcond
8054
8055 /*!
8056  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8057  * dimension and sharing the node coordinates array.
8058  * All cells of the first mesh precede all cells of the second mesh
8059  * within the result mesh. 
8060  *  \param [in] mesh1 - the first mesh.
8061  *  \param [in] mesh2 - the second mesh.
8062  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8063  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8064  *          is no more needed.
8065  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8066  *  \throw If the meshes do not share the node coordinates array.
8067  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8068  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8069  */
8070 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8071 {
8072   std::vector<const MEDCouplingUMesh *> tmp(2);
8073   tmp[0]=mesh1; tmp[1]=mesh2;
8074   return MergeUMeshesOnSameCoords(tmp);
8075 }
8076
8077 /*!
8078  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8079  * dimension and sharing the node coordinates array.
8080  * All cells of the *i*-th mesh precede all cells of the
8081  * (*i*+1)-th mesh within the result mesh.
8082  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8083  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8084  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8085  *          is no more needed.
8086  *  \throw If \a a.size() == 0.
8087  *  \throw If \a a[ *i* ] == NULL.
8088  *  \throw If the meshes do not share the node coordinates array.
8089  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
8090  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8091  */
8092 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8093 {
8094   if(meshes.empty())
8095     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8096   for(std::size_t ii=0;ii<meshes.size();ii++)
8097     if(!meshes[ii])
8098       {
8099         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8100         throw INTERP_KERNEL::Exception(oss.str());
8101       }
8102   const DataArrayDouble *coords=meshes.front()->getCoords();
8103   int meshDim=meshes.front()->getMeshDimension();
8104   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8105   int meshLgth=0;
8106   int meshIndexLgth=0;
8107   for(;iter!=meshes.end();iter++)
8108     {
8109       if(coords!=(*iter)->getCoords())
8110         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8111       if(meshDim!=(*iter)->getMeshDimension())
8112         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8113       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8114       meshIndexLgth+=(*iter)->getNumberOfCells();
8115     }
8116   MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8117   nodal->alloc(meshLgth,1);
8118   int *nodalPtr=nodal->getPointer();
8119   MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8120   nodalIndex->alloc(meshIndexLgth+1,1);
8121   int *nodalIndexPtr=nodalIndex->getPointer();
8122   int offset=0;
8123   for(iter=meshes.begin();iter!=meshes.end();iter++)
8124     {
8125       const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8126       const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8127       int nbOfCells=(*iter)->getNumberOfCells();
8128       int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8129       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8130       if(iter!=meshes.begin())
8131         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8132       else
8133         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8134       offset+=meshLgth2;
8135     }
8136   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8137   ret->setName("merge");
8138   ret->setMeshDimension(meshDim);
8139   ret->setConnectivity(nodal,nodalIndex,true);
8140   ret->setCoords(coords);
8141   return ret;
8142 }
8143
8144 /*!
8145  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8146  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8147  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8148  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8149  * New" mode are returned for each input mesh.
8150  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8151  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
8152  *          valid values [0,1,2], see zipConnectivityTraducer().
8153  *  \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8154  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8155  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
8156  *          no more needed.
8157  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8158  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8159  *          is no more needed.
8160  *  \throw If \a meshes.size() == 0.
8161  *  \throw If \a meshes[ *i* ] == NULL.
8162  *  \throw If the meshes do not share the node coordinates array.
8163  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8164  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
8165  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8166  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
8167  */
8168 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8169 {
8170   //All checks are delegated to MergeUMeshesOnSameCoords
8171   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8172   MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8173   corr.resize(meshes.size());
8174   std::size_t nbOfMeshes=meshes.size();
8175   int offset=0;
8176   const int *o2nPtr=o2n->getConstPointer();
8177   for(std::size_t i=0;i<nbOfMeshes;i++)
8178     {
8179       DataArrayInt *tmp=DataArrayInt::New();
8180       int curNbOfCells=meshes[i]->getNumberOfCells();
8181       tmp->alloc(curNbOfCells,1);
8182       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8183       offset+=curNbOfCells;
8184       tmp->setName(meshes[i]->getName());
8185       corr[i]=tmp;
8186     }
8187   return ret.retn();
8188 }
8189
8190 /*!
8191  * Makes all given meshes share the nodal connectivity array. The common connectivity
8192  * array is created by concatenating the connectivity arrays of all given meshes. All
8193  * the given meshes must be of the same space dimension but dimension of cells **can
8194  * differ**. This method is particulary useful in MEDLoader context to build a \ref
8195  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8196  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8197  *  \param [in,out] meshes - a vector of meshes to update.
8198  *  \throw If any of \a meshes is NULL.
8199  *  \throw If the coordinates array is not set in any of \a meshes.
8200  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8201  *  \throw If \a meshes are of different space dimension.
8202  */
8203 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8204 {
8205   std::size_t sz=meshes.size();
8206   if(sz==0 || sz==1)
8207     return;
8208   std::vector< const DataArrayDouble * > coords(meshes.size());
8209   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8210   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8211     {
8212       if((*it))
8213         {
8214           (*it)->checkConnectivityFullyDefined();
8215           const DataArrayDouble *coo=(*it)->getCoords();
8216           if(coo)
8217             *it2=coo;
8218           else
8219             {
8220               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8221               oss << " has no coordinate array defined !";
8222               throw INTERP_KERNEL::Exception(oss.str());
8223             }
8224         }
8225       else
8226         {
8227           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8228           oss << " is null !";
8229           throw INTERP_KERNEL::Exception(oss.str());
8230         }
8231     }
8232   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8233   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8234   int offset=(*it)->getNumberOfNodes();
8235   (*it++)->setCoords(res);
8236   for(;it!=meshes.end();it++)
8237     {
8238       int oldNumberOfNodes=(*it)->getNumberOfNodes();
8239       (*it)->setCoords(res);
8240       (*it)->shiftNodeNumbersInConn(offset);
8241       offset+=oldNumberOfNodes;
8242     }
8243 }
8244
8245 /*!
8246  * Merges nodes coincident with a given precision within all given meshes that share
8247  * the nodal connectivity array. The given meshes **can be of different** mesh
8248  * dimension. This method is particulary useful in MEDLoader context to build a \ref
8249  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8250  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. 
8251  *  \param [in,out] meshes - a vector of meshes to update.
8252  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8253  *  \throw If any of \a meshes is NULL.
8254  *  \throw If the \a meshes do not share the same node coordinates array.
8255  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8256  */
8257 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8258 {
8259   if(meshes.empty())
8260     return ;
8261   std::set<const DataArrayDouble *> s;
8262   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8263     {
8264       if(*it)
8265         s.insert((*it)->getCoords());
8266       else
8267         {
8268           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 !";
8269           throw INTERP_KERNEL::Exception(oss.str());
8270         }
8271     }
8272   if(s.size()!=1)
8273     {
8274       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 !";
8275       throw INTERP_KERNEL::Exception(oss.str());
8276     }
8277   const DataArrayDouble *coo=*(s.begin());
8278   if(!coo)
8279     return;
8280   //
8281   DataArrayInt *comm,*commI;
8282   coo->findCommonTuples(eps,-1,comm,commI);
8283   MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8284   int oldNbOfNodes=coo->getNumberOfTuples();
8285   int newNbOfNodes;
8286   MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8287   if(oldNbOfNodes==newNbOfNodes)
8288     return ;
8289   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8290   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8291     {
8292       (*it)->renumberNodesInConn(o2n->getConstPointer());
8293       (*it)->setCoords(newCoords);
8294     } 
8295 }
8296
8297 /*!
8298  * This method takes in input a cell defined by its MEDcouplingUMesh connectivity [ \a connBg , \a connEnd ) and returns its extruded cell by inserting the result at the end of ret.
8299  * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8300  * \param isQuad specifies the policy of connectivity.
8301  * @ret in/out parameter in which the result will be append
8302  */
8303 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8304 {
8305   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8306   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8307   ret.push_back(cm.getExtrudedType());
8308   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8309   switch(flatType)
8310   {
8311     case INTERP_KERNEL::NORM_POINT1:
8312       {
8313         ret.push_back(connBg[1]);
8314         ret.push_back(connBg[1]+nbOfNodesPerLev);
8315         break;
8316       }
8317     case INTERP_KERNEL::NORM_SEG2:
8318       {
8319         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8320         ret.insert(ret.end(),conn,conn+4);
8321         break;
8322       }
8323     case INTERP_KERNEL::NORM_SEG3:
8324       {
8325         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8326         ret.insert(ret.end(),conn,conn+8);
8327         break;
8328       }
8329     case INTERP_KERNEL::NORM_QUAD4:
8330       {
8331         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8332         ret.insert(ret.end(),conn,conn+8);
8333         break;
8334       }
8335     case INTERP_KERNEL::NORM_TRI3:
8336       {
8337         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8338         ret.insert(ret.end(),conn,conn+6);
8339         break;
8340       }
8341     case INTERP_KERNEL::NORM_TRI6:
8342       {
8343         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,
8344           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8345         ret.insert(ret.end(),conn,conn+15);
8346         break;
8347       }
8348     case INTERP_KERNEL::NORM_QUAD8:
8349       {
8350         int conn[20]={
8351           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8352           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8353           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8354         };
8355         ret.insert(ret.end(),conn,conn+20);
8356         break;
8357       }
8358     case INTERP_KERNEL::NORM_POLYGON:
8359       {
8360         std::back_insert_iterator< std::vector<int> > ii(ret);
8361         std::copy(connBg+1,connEnd,ii);
8362         *ii++=-1;
8363         std::reverse_iterator<const int *> rConnBg(connEnd);
8364         std::reverse_iterator<const int *> rConnEnd(connBg+1);
8365         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8366         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8367         for(std::size_t i=0;i<nbOfRadFaces;i++)
8368           {
8369             *ii++=-1;
8370             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8371             std::copy(conn,conn+4,ii);
8372           }
8373         break;
8374       }
8375     default:
8376       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8377   }
8378 }
8379
8380 /*!
8381  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8382  */
8383 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8384 {
8385   std::size_t i, ip1;
8386   double v[3]={0.,0.,0.};
8387   std::size_t sz=std::distance(begin,end);
8388   if(isQuadratic)
8389     sz/=2;
8390   for(i=0;i<sz;i++)
8391     {
8392       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];
8393       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8394       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8395     }
8396   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8397
8398   // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8399   // SEG3 forming a circle):
8400   if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8401     {
8402       v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8403       for(std::size_t j=0;j<sz;j++)
8404         {
8405           if (j%2)  // current point i is quadratic, next point i+1 is standard
8406             {
8407               i = sz+j;
8408               ip1 = (j+1)%sz; // ip1 = "i+1"
8409             }
8410           else      // current point i is standard, next point i+1 is quadratic
8411             {
8412               i = j;
8413               ip1 = j+sz;
8414             }
8415           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8416           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8417           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8418         }
8419       ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8420     }
8421   return (ret>0.);
8422 }
8423
8424 /*!
8425  * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8426  */
8427 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8428 {
8429   std::vector<std::pair<int,int> > edges;
8430   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8431   const int *bgFace=begin;
8432   for(std::size_t i=0;i<nbOfFaces;i++)
8433     {
8434       const int *endFace=std::find(bgFace+1,end,-1);
8435       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8436       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8437         {
8438           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8439           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8440             return false;
8441           edges.push_back(p1);
8442         }
8443       bgFace=endFace+1;
8444     }
8445   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8446 }
8447
8448 /*!
8449  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8450  */
8451 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8452 {
8453   double vec0[3],vec1[3];
8454   std::size_t sz=std::distance(begin,end);
8455   if(sz%2!=0)
8456     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8457   int nbOfNodes=(int)sz/2;
8458   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8459   const double *pt0=coords+3*begin[0];
8460   const double *pt1=coords+3*begin[nbOfNodes];
8461   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8462   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8463 }
8464
8465 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8466 {
8467   std::size_t sz=std::distance(begin,end);
8468   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8469   std::size_t nbOfNodes(sz/2);
8470   std::copy(begin,end,(int *)tmp);
8471   for(std::size_t j=1;j<nbOfNodes;j++)
8472     {
8473       begin[j]=tmp[nbOfNodes-j];
8474       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8475     }
8476 }
8477
8478 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8479 {
8480   std::size_t sz=std::distance(begin,end);
8481   if(sz!=4)
8482     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8483   double vec0[3],vec1[3];
8484   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8485   vec0[0]=pt1[0]-pt0[0]; vec0[1]=pt1[1]-pt0[1]; vec0[2]=pt1[2]-pt0[2]; vec1[0]=pt2[0]-pt0[0]; vec1[1]=pt2[1]-pt0[1]; vec1[2]=pt2[2]-pt0[2]; 
8486   return ((vec0[1]*vec1[2]-vec0[2]*vec1[1])*(pt3[0]-pt0[0])+(vec0[2]*vec1[0]-vec0[0]*vec1[2])*(pt3[1]-pt0[1])+(vec0[0]*vec1[1]-vec0[1]*vec1[0])*(pt3[2]-pt0[2]))<0;
8487 }
8488
8489 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8490 {
8491   std::size_t sz=std::distance(begin,end);
8492   if(sz!=5)
8493     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8494   double vec0[3];
8495   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8496   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8497   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8498 }
8499
8500 /*!
8501  * 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 ) 
8502  * 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
8503  * a 2D space.
8504  *
8505  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8506  * \param [in] coords the coordinates with nb of components exactly equal to 3
8507  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8508  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8509  * \param [out] res the result is put at the end of the vector without any alteration of the data.
8510  */
8511 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8512 {
8513   int nbFaces=std::count(begin+1,end,-1)+1;
8514   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8515   double *vPtr=v->getPointer();
8516   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8517   double *pPtr=p->getPointer();
8518   const int *stFaceConn=begin+1;
8519   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8520     {
8521       const int *endFaceConn=std::find(stFaceConn,end,-1);
8522       ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8523       stFaceConn=endFaceConn+1;
8524     }
8525   pPtr=p->getPointer(); vPtr=v->getPointer();
8526   DataArrayInt *comm1=0,*commI1=0;
8527   v->findCommonTuples(eps,-1,comm1,commI1);
8528   MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8529   const int *comm1Ptr=comm1->getConstPointer();
8530   const int *commI1Ptr=commI1->getConstPointer();
8531   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8532   res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8533   //
8534   MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8535   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8536   mm->finishInsertingCells();
8537   //
8538   for(int i=0;i<nbOfGrps1;i++)
8539     {
8540       int vecId=comm1Ptr[commI1Ptr[i]];
8541       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8542       DataArrayInt *comm2=0,*commI2=0;
8543       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8544       MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8545       const int *comm2Ptr=comm2->getConstPointer();
8546       const int *commI2Ptr=commI2->getConstPointer();
8547       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8548       for(int j=0;j<nbOfGrps2;j++)
8549         {
8550           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8551             {
8552               res->insertAtTheEnd(begin,end);
8553               res->pushBackSilent(-1);
8554             }
8555           else
8556             {
8557               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8558               MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8559               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8560               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8561               MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8562               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8563               MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8564               MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8565               const int *idsNodePtr=idsNode->getConstPointer();
8566               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];
8567               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8568               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8569               if(std::abs(norm)>eps)
8570                 {
8571                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8572                   mm3->rotate(center,vec,angle);
8573                 }
8574               mm3->changeSpaceDimension(2);
8575               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8576               const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8577               const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8578               int nbOfCells=mm4->getNumberOfCells();
8579               for(int k=0;k<nbOfCells;k++)
8580                 {
8581                   int l=0;
8582                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8583                     res->pushBackSilent(idsNodePtr[*work]);
8584                   res->pushBackSilent(-1);
8585                 }
8586             }
8587         }
8588     }
8589   res->popBackSilent();
8590 }
8591
8592 /*!
8593  * 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
8594  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8595  * 
8596  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8597  * \param [in] coords coordinates expected to have 3 components.
8598  * \param [in] begin start of the nodal connectivity of the face.
8599  * \param [in] end end of the nodal connectivity (excluded) of the face.
8600  * \param [out] v the normalized vector of size 3
8601  * \param [out] p the pos of plane
8602  */
8603 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8604 {
8605   std::size_t nbPoints=std::distance(begin,end);
8606   if(nbPoints<3)
8607     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8608   double vec[3]={0.,0.,0.};
8609   std::size_t j=0;
8610   bool refFound=false;
8611   for(;j<nbPoints-1 && !refFound;j++)
8612     {
8613       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8614       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8615       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8616       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8617       if(norm>eps)
8618         {
8619           refFound=true;
8620           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8621         }
8622     }
8623   for(std::size_t i=j;i<nbPoints-1;i++)
8624     {
8625       double curVec[3];
8626       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8627       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8628       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8629       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8630       if(norm<eps)
8631         continue;
8632       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8633       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];
8634       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8635       if(norm>eps)
8636         {
8637           v[0]/=norm; v[1]/=norm; v[2]/=norm;
8638           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8639           return ;
8640         }
8641     }
8642   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8643 }
8644
8645 /*!
8646  * This method tries to obtain a well oriented polyhedron.
8647  * If the algorithm fails, an exception will be thrown.
8648  */
8649 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8650 {
8651   std::list< std::pair<int,int> > edgesOK,edgesFinished;
8652   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8653   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8654   isPerm[0]=true;
8655   int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8656   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8657   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8658   //
8659   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8660     {
8661       bgFace=begin;
8662       std::size_t smthChanged=0;
8663       for(std::size_t i=0;i<nbOfFaces;i++)
8664         {
8665           endFace=std::find(bgFace+1,end,-1);
8666           nbOfEdgesInFace=std::distance(bgFace,endFace);
8667           if(!isPerm[i])
8668             {
8669               bool b;
8670               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8671                 {
8672                   std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8673                   std::pair<int,int> p2(p1.second,p1.first);
8674                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8675                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8676                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8677                 }
8678               if(isPerm[i])
8679                 { 
8680                   if(!b)
8681                     std::reverse(bgFace+1,endFace);
8682                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8683                     {
8684                       std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8685                       std::pair<int,int> p2(p1.second,p1.first);
8686                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8687                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8688                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8689                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
8690                       std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8691                       if(it!=edgesOK.end())
8692                         {
8693                           edgesOK.erase(it);
8694                           edgesFinished.push_back(p1);
8695                         }
8696                       else
8697                         edgesOK.push_back(p1);
8698                     }
8699                 }
8700             }
8701           bgFace=endFace+1;
8702         }
8703       if(smthChanged==0)
8704         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8705     }
8706   if(!edgesOK.empty())
8707     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8708   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8709     {//not lucky ! The first face was not correctly oriented : reorient all faces...
8710       bgFace=begin;
8711       for(std::size_t i=0;i<nbOfFaces;i++)
8712         {
8713           endFace=std::find(bgFace+1,end,-1);
8714           std::reverse(bgFace+1,endFace);
8715           bgFace=endFace+1;
8716         }
8717     }
8718 }
8719
8720 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8721 {
8722   int nbOfNodesExpected(skin->getNumberOfNodes());
8723   const int *n2oPtr(n2o->getConstPointer());
8724   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8725   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8726   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8727   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8728   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8729   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8730   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_POLYGON;
8731   if(nbOfNodesExpected<1)
8732     return ret.retn();
8733   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8734   *work++=n2oPtr[prevNode];
8735   for(int i=1;i<nbOfNodesExpected;i++)
8736     {
8737       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8738         {
8739           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8740           conn.erase(prevNode);
8741           if(conn.size()==1)
8742             {
8743               int curNode(*(conn.begin()));
8744               *work++=n2oPtr[curNode];
8745               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8746               shar.erase(prevCell);
8747               if(shar.size()==1)
8748                 {
8749                   prevCell=*(shar.begin());
8750                   prevNode=curNode;
8751                 }
8752               else
8753                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8754             }
8755           else
8756             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8757         }
8758       else
8759         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8760     }
8761   return ret.retn();
8762 }
8763
8764 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8765 {
8766   int nbOfNodesExpected(skin->getNumberOfNodes());
8767   int nbOfTurn(nbOfNodesExpected/2);
8768   const int *n2oPtr(n2o->getConstPointer());
8769   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8770   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8771   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8772   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8773   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8774   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8775   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_QPOLYG;
8776   if(nbOfNodesExpected<1)
8777     return ret.retn();
8778   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8779   *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8780   for(int i=1;i<nbOfTurn;i++)
8781     {
8782       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8783         {
8784           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8785           conn.erase(prevNode);
8786           if(conn.size()==1)
8787             {
8788               int curNode(*(conn.begin()));
8789               *work=n2oPtr[curNode];
8790               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8791               shar.erase(prevCell);
8792               if(shar.size()==1)
8793                 {
8794                   int curCell(*(shar.begin()));
8795                   work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8796                   prevCell=curCell;
8797                   prevNode=curNode;
8798                   work++;
8799                 }
8800               else
8801                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8802             }
8803           else
8804             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8805         }
8806       else
8807         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8808     }
8809   return ret.retn();
8810 }
8811
8812 /*!
8813  * This method makes the assumption spacedimension == meshdimension == 2.
8814  * This method works only for linear cells.
8815  * 
8816  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8817  */
8818 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8819 {
8820   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8821     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8822   MCAuto<MEDCouplingUMesh> skin(computeSkin());
8823   int oldNbOfNodes(skin->getNumberOfNodes());
8824   MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8825   int nbOfNodesExpected(skin->getNumberOfNodes());
8826   MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8827   int nbCells(skin->getNumberOfCells());
8828   if(nbCells==nbOfNodesExpected)
8829     return buildUnionOf2DMeshLinear(skin,n2o);
8830   else if(2*nbCells==nbOfNodesExpected)
8831     return buildUnionOf2DMeshQuadratic(skin,n2o);
8832   else
8833     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8834 }
8835
8836 /*!
8837  * This method makes the assumption spacedimension == meshdimension == 3.
8838  * This method works only for linear cells.
8839  * 
8840  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8841  */
8842 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8843 {
8844   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8845     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8846   MCAuto<MEDCouplingUMesh> m=computeSkin();
8847   const int *conn=m->getNodalConnectivity()->getConstPointer();
8848   const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8849   int nbOfCells=m->getNumberOfCells();
8850   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8851   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
8852   if(nbOfCells<1)
8853     return ret.retn();
8854   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8855   for(int i=1;i<nbOfCells;i++)
8856     {
8857       *work++=-1;
8858       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8859     }
8860   return ret.retn();
8861 }
8862
8863 /*!
8864  * \brief Creates a graph of cell neighbors
8865  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8866  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
8867  *  For example
8868  *  - index:  0 3 5 6 6
8869  *  - value:  1 2 3 2 3 3
8870  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8871  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8872  */
8873 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8874 {
8875   checkConnectivityFullyDefined();
8876
8877   int meshDim = this->getMeshDimension();
8878   MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8879   MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8880   this->getReverseNodalConnectivity(revConn,indexr);
8881   const int* indexr_ptr=indexr->getConstPointer();
8882   const int* revConn_ptr=revConn->getConstPointer();
8883
8884   const MEDCoupling::DataArrayInt* index;
8885   const MEDCoupling::DataArrayInt* conn;
8886   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8887   index=this->getNodalConnectivityIndex();
8888   int nbCells=this->getNumberOfCells();
8889   const int* index_ptr=index->getConstPointer();
8890   const int* conn_ptr=conn->getConstPointer();
8891
8892   //creating graph arcs (cell to cell relations)
8893   //arcs are stored in terms of (index,value) notation
8894   // 0 3 5 6 6
8895   // 1 2 3 2 3 3
8896   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8897   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8898
8899   //warning here one node have less than or equal effective number of cell with it
8900   //but cell could have more than effective nodes
8901   //because other equals nodes in other domain (with other global inode)
8902   std::vector <int> cell2cell_index(nbCells+1,0);
8903   std::vector <int> cell2cell;
8904   cell2cell.reserve(3*nbCells);
8905
8906   for (int icell=0; icell<nbCells;icell++)
8907     {
8908       std::map<int,int > counter;
8909       for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8910         {
8911           int inode=conn_ptr[iconn];
8912           for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8913             {
8914               int icell2=revConn_ptr[iconnr];
8915               std::map<int,int>::iterator iter=counter.find(icell2);
8916               if (iter!=counter.end()) (iter->second)++;
8917               else counter.insert(std::make_pair(icell2,1));
8918             }
8919         }
8920       for (std::map<int,int>::const_iterator iter=counter.begin();
8921            iter!=counter.end(); iter++)
8922         if (iter->second >= meshDim)
8923           {
8924             cell2cell_index[icell+1]++;
8925             cell2cell.push_back(iter->first);
8926           }
8927     }
8928   indexr->decrRef();
8929   revConn->decrRef();
8930   cell2cell_index[0]=0;
8931   for (int icell=0; icell<nbCells;icell++)
8932     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8933
8934   //filling up index and value to create skylinearray structure
8935   MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8936   return array;
8937 }
8938
8939 /*!
8940  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8941  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8942  */
8943 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8944 {
8945   double *w=zipFrmt;
8946   if(spaceDim==3)
8947     for(int i=0;i<nbOfNodesInCell;i++)
8948       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8949   else if(spaceDim==2)
8950     {
8951       for(int i=0;i<nbOfNodesInCell;i++)
8952         {
8953           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8954           *w++=0.;
8955         }
8956     }
8957   else
8958     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8959 }
8960
8961 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8962 {
8963   int nbOfCells=getNumberOfCells();
8964   if(nbOfCells<=0)
8965     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8966   ofs << "  <" << getVTKDataSetType() << ">\n";
8967   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8968   ofs << "      <PointData>\n" << pointData << std::endl;
8969   ofs << "      </PointData>\n";
8970   ofs << "      <CellData>\n" << cellData << std::endl;
8971   ofs << "      </CellData>\n";
8972   ofs << "      <Points>\n";
8973   if(getSpaceDimension()==3)
8974     _coords->writeVTK(ofs,8,"Points",byteData);
8975   else
8976     {
8977       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8978       coo->writeVTK(ofs,8,"Points",byteData);
8979     }
8980   ofs << "      </Points>\n";
8981   ofs << "      <Cells>\n";
8982   const int *cPtr=_nodal_connec->getConstPointer();
8983   const int *cIPtr=_nodal_connec_index->getConstPointer();
8984   MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8985   MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8986   MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8987   MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8988   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8989   int szFaceOffsets=0,szConn=0;
8990   for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8991     {
8992       *w2=cPtr[cIPtr[i]];
8993       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8994         {
8995           *w1=-1;
8996           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8997           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8998         }
8999       else
9000         {
9001           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
9002           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
9003           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
9004           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
9005           w4=std::copy(c.begin(),c.end(),w4);
9006         }
9007     }
9008   types->transformWithIndArr(MEDCOUPLING2VTKTYPETRADUCER,MEDCOUPLING2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
9009   types->writeVTK(ofs,8,"UInt8","types",byteData);
9010   offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
9011   if(szFaceOffsets!=0)
9012     {//presence of Polyhedra
9013       connectivity->reAlloc(szConn);
9014       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
9015       MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
9016       w1=faces->getPointer();
9017       for(int i=0;i<nbOfCells;i++)
9018         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
9019           {
9020             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
9021             *w1++=nbFaces;
9022             const int *w6=cPtr+cIPtr[i]+1,*w5=0;
9023             for(int j=0;j<nbFaces;j++)
9024               {
9025                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9026                 *w1++=(int)std::distance(w6,w5);
9027                 w1=std::copy(w6,w5,w1);
9028                 w6=w5+1;
9029               }
9030           }
9031       faces->writeVTK(ofs,8,"Int32","faces",byteData);
9032     }
9033   connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9034   ofs << "      </Cells>\n";
9035   ofs << "    </Piece>\n";
9036   ofs << "  </" << getVTKDataSetType() << ">\n";
9037 }
9038
9039 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9040 {
9041   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9042   if(_mesh_dim==-2)
9043     { stream << " Not set !"; return ; }
9044   stream << " Mesh dimension : " << _mesh_dim << ".";
9045   if(_mesh_dim==-1)
9046     return ;
9047   if(!_coords)
9048     { stream << " No coordinates set !"; return ; }
9049   if(!_coords->isAllocated())
9050     { stream << " Coordinates set but not allocated !"; return ; }
9051   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9052   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9053   if(!_nodal_connec_index)
9054     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9055   if(!_nodal_connec_index->isAllocated())
9056     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9057   int lgth=_nodal_connec_index->getNumberOfTuples();
9058   int cpt=_nodal_connec_index->getNumberOfComponents();
9059   if(cpt!=1 || lgth<1)
9060     return ;
9061   stream << std::endl << "Number of cells : " << lgth-1 << ".";
9062 }
9063
9064 std::string MEDCouplingUMesh::getVTKDataSetType() const
9065 {
9066   return std::string("UnstructuredGrid");
9067 }
9068
9069 std::string MEDCouplingUMesh::getVTKFileExtension() const
9070 {
9071   return std::string("vtu");
9072 }
9073
9074 /*!
9075  * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9076  * returns a result mesh constituted by polygons.
9077  * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9078  * all nodes from m2.
9079  * The meshes should be in 2D space. In
9080  * addition, returns two arrays mapping cells of the result mesh to cells of the input
9081  * meshes.
9082  *  \param [in] m1 - the first input mesh which is a partitioned object. The mesh must be so that each point in the space covered by \a m1
9083  *                      must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9084  *  \param [in] m2 - the second input mesh which is a partition tool. The mesh must be so that each point in the space covered by \a m2
9085  *                      must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9086  *  \param [in] eps - precision used to detect coincident mesh entities.
9087  *  \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9088  *         cell an id of the cell of \a m1 it comes from. The caller is to delete
9089  *         this array using decrRef() as it is no more needed.
9090  *  \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9091  *         cell an id of the cell of \a m2 it comes from. -1 value means that a
9092  *         result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9093  *         any cell of \a m2. The caller is to delete this array using decrRef() as
9094  *         it is no more needed.  
9095  *  \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9096  *         MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9097  *         is no more needed.  
9098  *  \throw If the coordinates array is not set in any of the meshes.
9099  *  \throw If the nodal connectivity of cells is not defined in any of the meshes.
9100  *  \throw If any of the meshes is not a 2D mesh in 2D space.
9101  *
9102  *  \sa conformize2D, mergeNodes
9103  */
9104 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9105                                                       double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9106 {
9107   if(!m1 || !m2)
9108     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9109   m1->checkFullyDefined();
9110   m2->checkFullyDefined();
9111   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9112     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
9113
9114   // Step 1: compute all edge intersections (new nodes)
9115   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9116   MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9117   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9118   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9119   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9120                               m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9121                               addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9122   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9123   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9124   MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9125
9126   // Step 2: re-order newly created nodes according to the ordering found in m2
9127   std::vector< std::vector<int> > intersectEdge2;
9128   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9129   subDiv2.clear(); dd5=0; dd6=0;
9130
9131   // Step 3:
9132   std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9133   std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9134   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9135                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9136
9137   // Step 4: Prepare final result:
9138   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9139   addCooDa->alloc((int)(addCoo.size())/2,2);
9140   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9141   MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9142   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9143   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9144   std::vector<const DataArrayDouble *> coordss(4);
9145   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9146   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9147   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9148   MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9149   MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9150   MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9151   MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9152   ret->setConnectivity(conn,connI,true);
9153   ret->setCoords(coo);
9154   cellNb1=c1.retn(); cellNb2=c2.retn();
9155   return ret.retn();
9156 }
9157
9158 /// @cond INTERNAL
9159
9160 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9161 {
9162   if(candidates.empty())
9163     return false;
9164   for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9165     {
9166       const std::vector<int>& pool(intersectEdge1[*it]);
9167       int tmp[2]; tmp[0]=start; tmp[1]=stop;
9168       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9169         {
9170           retVal=*it+1;
9171           return true;
9172         }
9173       tmp[0]=stop; tmp[1]=start;
9174       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9175         {
9176           retVal=-*it-1;
9177           return true;
9178         }
9179     }
9180   return false;
9181 }
9182
9183 MEDCouplingUMesh *BuildMesh1DCutFrom(const MEDCouplingUMesh *mesh1D, const std::vector< std::vector<int> >& intersectEdge2, const DataArrayDouble *coords1, const std::vector<double>& addCoo, const std::map<int,int>& mergedNodes, const std::vector< std::vector<int> >& colinear2, const std::vector< std::vector<int> >& intersectEdge1,
9184                                      MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9185 {
9186   idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9187   idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9188   int nCells(mesh1D->getNumberOfCells());
9189   if(nCells!=(int)intersectEdge2.size())
9190     throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9191   const DataArrayDouble *coo2(mesh1D->getCoords());
9192   const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9193   const double *coo2Ptr(coo2->begin());
9194   int offset1(coords1->getNumberOfTuples());
9195   int offset2(offset1+coo2->getNumberOfTuples());
9196   int offset3(offset2+addCoo.size()/2);
9197   std::vector<double> addCooQuad;
9198   MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9199   int tmp[4],cicnt(0),kk(0);
9200   for(int i=0;i<nCells;i++)
9201     {
9202       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9203       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9204       const std::vector<int>& subEdges(intersectEdge2[i]);
9205       int nbSubEdge(subEdges.size()/2);
9206       for(int j=0;j<nbSubEdge;j++,kk++)
9207         {
9208           MCAuto<INTERP_KERNEL::Node> n1(MEDCouplingUMeshBuildQPNode(subEdges[2*j],coords1->begin(),offset1,coo2Ptr,offset2,addCoo)),n2(MEDCouplingUMeshBuildQPNode(subEdges[2*j+1],coords1->begin(),offset1,coo2Ptr,offset2,addCoo));
9209           MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9210           INTERP_KERNEL::Edge *e2Ptr(e2);
9211           std::map<int,int>::const_iterator itm;
9212           if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9213             {
9214               tmp[0]=INTERP_KERNEL::NORM_SEG3;
9215               itm=mergedNodes.find(subEdges[2*j]);
9216               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9217               itm=mergedNodes.find(subEdges[2*j+1]);
9218               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9219               tmp[3]=offset3+(int)addCooQuad.size()/2;
9220               double tmp2[2];
9221               e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9222               cicnt+=4;
9223               cOut->insertAtTheEnd(tmp,tmp+4);
9224               ciOut->pushBackSilent(cicnt);
9225             }
9226           else
9227             {
9228               tmp[0]=INTERP_KERNEL::NORM_SEG2;
9229               itm=mergedNodes.find(subEdges[2*j]);
9230               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9231               itm=mergedNodes.find(subEdges[2*j+1]);
9232               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9233               cicnt+=3;
9234               cOut->insertAtTheEnd(tmp,tmp+3);
9235               ciOut->pushBackSilent(cicnt);
9236             }
9237           int tmp00;
9238           if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9239             {
9240               idsInRetColinear->pushBackSilent(kk);
9241               idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9242             }
9243         }
9244       e->decrRef();
9245     }
9246   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9247   ret->setConnectivity(cOut,ciOut,true);
9248   MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9249   arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9250   MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9251   std::vector<const DataArrayDouble *> coordss(4);
9252   coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9253   MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9254   ret->setCoords(arr);
9255   return ret.retn();
9256 }
9257
9258 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9259 {
9260   std::vector<int> allEdges;
9261   for(const int *it2(descBg);it2!=descEnd;it2++)
9262     {
9263       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9264       if(*it2>0)
9265         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9266       else
9267         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9268     }
9269   std::size_t nb(allEdges.size());
9270   if(nb%2!=0)
9271     throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9272   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9273   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9274   ret->setCoords(coords);
9275   ret->allocateCells(1);
9276   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9277   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9278     connOut[kk]=allEdges[2*kk];
9279   ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9280   return ret.retn();
9281 }
9282
9283 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9284 {
9285   const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9286   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9287   std::size_t ii(0);
9288   unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9289   if(sz!=std::distance(descBg,descEnd))
9290     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9291   INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9292   std::vector<int> allEdges,centers;
9293   const double *coordsPtr(coords->begin());
9294   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9295   int offset(coords->getNumberOfTuples());
9296   for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9297     {
9298       INTERP_KERNEL::NormalizedCellType typeOfSon;
9299       cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9300       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9301       if(*it2>0)
9302         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9303       else
9304         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9305       if(edge1.size()==2)
9306         centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9307       else
9308         {//the current edge has been subsplit -> create corresponding centers.
9309           std::size_t nbOfCentersToAppend(edge1.size()/2);
9310           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9311           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9312           std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9313           for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9314             {
9315               double tmpp[2];
9316               const double *aa(coordsPtr+2*(*it3++));
9317               const double *bb(coordsPtr+2*(*it3++));
9318               ee->getMiddleOfPoints(aa,bb,tmpp);
9319               addCoo->insertAtTheEnd(tmpp,tmpp+2);
9320               centers.push_back(offset+k);
9321             }
9322         }
9323     }
9324   std::size_t nb(allEdges.size());
9325   if(nb%2!=0)
9326     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9327   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9328   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9329   if(addCoo->empty())
9330     ret->setCoords(coords);
9331   else
9332     {
9333       addCoo->rearrange(2);
9334       addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9335       ret->setCoords(addCoo);
9336     }
9337   ret->allocateCells(1);
9338   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9339   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9340     connOut[kk]=allEdges[2*kk];
9341   connOut.insert(connOut.end(),centers.begin(),centers.end());
9342   ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9343   return ret.retn();
9344 }
9345
9346 /*!
9347  * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9348  * of those edges.
9349  *
9350  * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9351  */
9352 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9353 {
9354   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9355   if(!cm.isQuadratic())
9356     return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9357   else
9358     return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9359 }
9360
9361 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9362 {
9363   bool isQuad(false);
9364   for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9365     {
9366       const INTERP_KERNEL::Edge *ee(*it);
9367       if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9368         isQuad=true;
9369     }
9370   if(!isQuad)
9371     mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9372   else
9373     {
9374       const double *coo(mesh2D->getCoords()->begin());
9375       std::size_t sz(conn.size());
9376       std::vector<double> addCoo;
9377       std::vector<int> conn2(conn);
9378       int offset(mesh2D->getNumberOfNodes());
9379       for(std::size_t i=0;i<sz;i++)
9380         {
9381           double tmp[2];
9382           edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9383           addCoo.insert(addCoo.end(),tmp,tmp+2);
9384           conn2.push_back(offset+(int)i);
9385         }
9386       mesh2D->getCoords()->rearrange(1);
9387       mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9388       mesh2D->getCoords()->rearrange(2);
9389       mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9390     }
9391 }
9392
9393 /*!
9394  * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9395  *
9396  * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9397  * a set of edges defined in \a splitMesh1D.
9398  */
9399 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9400                              std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9401 {
9402   std::size_t nb(edge1Bis.size()/2);
9403   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9404   int iEnd(splitMesh1D->getNumberOfCells());
9405   if(iEnd==0)
9406     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9407   std::size_t ii,jj;
9408   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9409   for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9410   for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9411   //
9412   if(jj==nb)
9413     {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9414       out0.resize(1); out1.resize(1);
9415       std::vector<int>& connOut(out0[0]);
9416       connOut.resize(nbOfEdgesOf2DCellSplit);
9417       std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9418       edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9419       for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9420         {
9421           connOut[kk]=edge1Bis[2*kk];
9422           edgesPtr[kk]=edge1BisPtr[2*kk];
9423         }
9424     }
9425   else
9426     {
9427       // [i,iEnd[ contains the
9428       out0.resize(2); out1.resize(2);
9429       std::vector<int>& connOutLeft(out0[0]);
9430       std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9431       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9432       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9433       for(std::size_t k=ii;k<jj+1;k++)
9434         { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9435       std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9436       for(int ik=0;ik<iEnd;ik++)
9437         {
9438           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9439           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9440           ees[ik]=ee;
9441         }
9442       for(int ik=iEnd-1;ik>=0;ik--)
9443         connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9444       for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9445         { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9446       eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9447       for(int ik=0;ik<iEnd;ik++)
9448         connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9449       eright.insert(eright.end(),ees.begin(),ees.end());
9450     }
9451 }
9452
9453 /// @endcond
9454
9455 /// @cond INTERNAL
9456
9457 struct CellInfo
9458 {
9459 public:
9460   CellInfo() { }
9461   CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9462 public:
9463   std::vector<int> _edges;
9464   std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9465 };
9466
9467 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9468 {
9469   std::size_t nbe(edges.size());
9470   std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9471   for(std::size_t i=0;i<nbe;i++)
9472     {
9473       edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9474       edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9475     }
9476   _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9477   std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9478   std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9479 }
9480
9481 class EdgeInfo
9482 {
9483 public:
9484   EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9485   EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9486   bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9487   void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9488   void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9489 private:
9490   int _istart;
9491   int _iend;
9492   MCAuto<MEDCouplingUMesh> _mesh;
9493   MCAuto<INTERP_KERNEL::Edge> _edge;
9494   int _left;
9495   int _right;
9496 };
9497
9498 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9499 {
9500   const MEDCouplingUMesh *mesh(_mesh);
9501   if(mesh)
9502     return ;
9503   if(_right<pos)
9504     return ;
9505   if(_left>pos)
9506     { _left++; _right++; return ; }
9507   if(_right==pos)
9508     {
9509       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9510       if((isLeft && isRight) || (!isLeft && !isRight))
9511         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9512       if(isLeft)
9513         return ;
9514       if(isRight)
9515         {
9516           _right++;
9517           return ;
9518         }
9519     }
9520   if(_left==pos)
9521     {
9522       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9523       if((isLeft && isRight) || (!isLeft && !isRight))
9524         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9525       if(isLeft)
9526         {
9527           _right++;
9528           return ;
9529         }
9530       if(isRight)
9531         {
9532           _left++;
9533           _right++;
9534           return ;
9535         }
9536     }
9537 }
9538
9539 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9540 {
9541   const MEDCouplingUMesh *mesh(_mesh);
9542   if(!mesh)
9543     {
9544       neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9545     }
9546   else
9547     {// not fully splitting cell case
9548       if(mesh2D->getNumberOfCells()==1)
9549         {//little optimization. 1 cell no need to find in which cell mesh is !
9550           neighbors[0]=offset; neighbors[1]=offset;
9551           return;
9552         }
9553       else
9554         {
9555           MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9556           int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9557           if(cellId==-1)
9558             throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9559           neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9560         }
9561     }
9562 }
9563
9564 class VectorOfCellInfo
9565 {
9566 public:
9567   VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9568   std::size_t size() const { return _pool.size(); }
9569   int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9570   void setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs);
9571   const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9572   const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9573   MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9574   void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9575 private:
9576   int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9577   void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9578   const CellInfo& get(int pos) const;
9579   CellInfo& get(int pos);
9580 private:
9581   std::vector<CellInfo> _pool;
9582   MCAuto<MEDCouplingUMesh> _ze_mesh;
9583   std::vector<EdgeInfo> _edge_info;
9584 };
9585
9586 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9587 {
9588   _pool[0]._edges=edges;
9589   _pool[0]._edges_ptr=edgesPtr;
9590 }
9591
9592 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9593 {
9594   if(_pool.empty())
9595     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9596   if(_pool.size()==1)
9597     return 0;
9598   const MEDCouplingUMesh *zeMesh(_ze_mesh);
9599   if(!zeMesh)
9600     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9601   MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9602   return zeMesh->getCellContainingPoint(barys->begin(),eps);
9603 }
9604
9605 void VectorOfCellInfo::setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs)
9606 {
9607   get(pos);//to check pos
9608   bool isFast(pos==0 && _pool.size()==1);
9609   std::size_t sz(edges.size());
9610   // dealing with edges
9611   if(sz==1)
9612     _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9613   else
9614     _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9615   //
9616   std::vector<CellInfo> pool(_pool.size()-1+sz);
9617   for(int i=0;i<pos;i++)
9618     pool[i]=_pool[i];
9619   for(std::size_t j=0;j<sz;j++)
9620     pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9621   for(int i=pos+1;i<(int)_pool.size();i++)
9622     pool[i+sz-1]=_pool[i];
9623   _pool=pool;
9624   //
9625   if(sz==2)
9626     updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9627   //
9628   if(isFast)
9629     {
9630       _ze_mesh=mesh;
9631       return ;
9632     }
9633   //
9634   std::vector< MCAuto<MEDCouplingUMesh> > ms;
9635   if(pos>0)
9636     {
9637       MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9638       ms.push_back(elt);
9639     }
9640   ms.push_back(mesh);
9641   if(pos<_ze_mesh->getNumberOfCells()-1)
9642   {
9643     MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9644     ms.push_back(elt);
9645   }
9646   std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9647   for(std::size_t j=0;j<ms2.size();j++)
9648     ms2[j]=ms[j];
9649   _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9650 }
9651
9652 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9653 {
9654   _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9655 }
9656
9657 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9658 {
9659   if(pos<0)
9660     throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9661   int ret(0);
9662   for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9663     {
9664       if((*it).isInMyRange(pos))
9665         return ret;
9666     }
9667   throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9668 }
9669
9670 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9671 {
9672   get(pos);//to check;
9673   if(_edge_info.empty())
9674     return ;
9675   std::size_t sz(_edge_info.size()-1);
9676   for(std::size_t i=0;i<sz;i++)
9677     _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9678 }
9679
9680 const CellInfo& VectorOfCellInfo::get(int pos) const
9681 {
9682   if(pos<0 || pos>=(int)_pool.size())
9683     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9684   return _pool[pos];
9685 }
9686
9687 CellInfo& VectorOfCellInfo::get(int pos)
9688 {
9689   if(pos<0 || pos>=(int)_pool.size())
9690     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9691   return _pool[pos];
9692 }
9693
9694 /*!
9695  * Given :
9696  * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9697  * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9698  *
9699  * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9700  *
9701  * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9702  *
9703  * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9704  */
9705 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9706                                          MCAuto<DataArrayInt>& idsLeftRight)
9707 {
9708   int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9709   if(nbCellsInSplitMesh1D==0)
9710     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9711   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9712   std::size_t nb(allEdges.size()),jj;
9713   if(nb%2!=0)
9714     throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9715   std::vector<int> edge1Bis(nb*2);
9716   std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9717   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9718   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9719   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9720   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9721   //
9722   idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9723   int *idsLeftRightPtr(idsLeftRight->getPointer());
9724   VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9725   for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9726     {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9727       int iEnd(iStart);
9728       for(;iEnd<nbCellsInSplitMesh1D;)
9729         {
9730           for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9731           if(jj!=nb)
9732             break;
9733           else
9734             iEnd++;
9735         }
9736       if(iEnd<nbCellsInSplitMesh1D)
9737         iEnd++;
9738       //
9739       MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9740       int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9741       //
9742       MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9743       retTmp->setCoords(splitMesh1D->getCoords());
9744       retTmp->allocateCells();
9745
9746       std::vector< std::vector<int> > out0;
9747       std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9748
9749       BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9750       for(std::size_t cnt=0;cnt<out0.size();cnt++)
9751         AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9752       pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9753       //
9754       iStart=iEnd;
9755     }
9756   for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9757     pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9758   return pool.getZeMesh().retn();
9759 }
9760
9761 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9762                                      const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9763                                      MCAuto<DataArrayInt>& idsLeftRight)
9764 {
9765   const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9766   //
9767   std::vector<int> allEdges;
9768   std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9769   for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9770     {
9771       int edgeId(std::abs(*it)-1);
9772       std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9773       MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9774       const std::vector<int>& edge1(intersectEdge1[edgeId]);
9775       if(*it>0)
9776         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9777       else
9778         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9779       std::size_t sz(edge1.size());
9780       for(std::size_t cnt=0;cnt<sz;cnt++)
9781         allEdgesPtr.push_back(ee);
9782     }
9783   //
9784   return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9785 }
9786
9787 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9788 {
9789   if(!typ1.isQuadratic() && !typ2.isQuadratic())
9790     {//easy case comparison not
9791       return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9792     }
9793   else if(typ1.isQuadratic() && typ2.isQuadratic())
9794     {
9795       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9796       if(!status0)
9797         return false;
9798       if(conn1[2]==conn2[2])
9799         return true;
9800       const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9801       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9802       return dist<eps;
9803     }
9804   else
9805     {//only one is quadratic
9806       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9807       if(!status0)
9808         return false;
9809       const double *a(0),*bb(0),*be(0);
9810       if(typ1.isQuadratic())
9811         {
9812           a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9813         }
9814       else
9815         {
9816           a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9817         }
9818       double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9819       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9820       return dist<eps;
9821     }
9822 }
9823
9824 /*!
9825  * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9826  * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9827  *
9828  * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9829  */
9830 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9831 {
9832   if(candidatesIn2DEnd==candidatesIn2DBg)
9833     throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9834   const double *coo(mesh2DSplit->getCoords()->begin());
9835   if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9836     return *candidatesIn2DBg;
9837   int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9838   MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9839   if(cellIdInMesh1DSplitRelative<0)
9840     cur1D->changeOrientationOfCells();
9841   const int *c1D(cur1D->getNodalConnectivity()->begin());
9842   const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9843   for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9844     {
9845       MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9846       const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9847       const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9848       unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9849       INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9850       for(unsigned it2=0;it2<sz;it2++)
9851         {
9852           INTERP_KERNEL::NormalizedCellType typeOfSon;
9853           cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9854           const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9855           if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9856             return *it;
9857         }
9858     }
9859   throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9860 }
9861
9862 /// @endcond
9863
9864 /*!
9865  * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9866  * Thus the final result contains the aggregation of nodes of \a mesh2D, then nodes of \a mesh1D, then new nodes that are the result of the intersection
9867  * and finaly, in case of quadratic polygon the centers of edges new nodes.
9868  * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9869  *
9870  * \param [in] mesh2D - the 2D mesh (spacedim=meshdim=2) to be intersected using \a mesh1D tool. The mesh must be so that each point in the space covered by \a mesh2D
9871  *                      must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9872  * \param [in] mesh1D - the 1D mesh (spacedim=2 meshdim=1) the is the tool that will be used to intersect \a mesh2D. \a mesh1D must be ordered consecutively. If it is not the case
9873  *                      you can invoke orderConsecutiveCells1D on \a mesh1D.
9874  * \param [in] eps - precision used to perform intersections and localization operations.
9875  * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9876  * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9877  * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9878  *                               So this array has a number of tuples equal to the number of cells of \a splitMesh2D and a number of component equal to 1.
9879  * \param [out] cellIdInMesh1D - the array of pair that gives for each cell id \a i in \a splitMesh1D the cell in \a splitMesh2D on the left for the 1st component
9880  *                               and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9881  *                               So this array has a number of tuples equal to the number of cells of \a splitMesh1D and a number of components equal to 2.
9882  *
9883  * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9884  */
9885 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9886 {
9887   if(!mesh2D || !mesh1D)
9888     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9889   mesh2D->checkFullyDefined();
9890   mesh1D->checkFullyDefined();
9891   const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9892   if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9893     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9894   // Step 1: compute all edge intersections (new nodes)
9895   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9896   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9897   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9898   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9899   //
9900   // Build desc connectivity
9901   DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9902   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9903   MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9904   std::map<int,int> mergedNodes;
9905   Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9906   // use mergeNodes to fix intersectEdge1
9907   for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9908     {
9909       std::size_t n((*it0).size()/2);
9910       int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9911       std::map<int,int>::const_iterator it1;
9912       it1=mergedNodes.find(eltStart);
9913       if(it1!=mergedNodes.end())
9914         (*it0)[0]=(*it1).second;
9915       it1=mergedNodes.find(eltEnd);
9916       if(it1!=mergedNodes.end())
9917         (*it0)[2*n-1]=(*it1).second;
9918     }
9919   //
9920   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9921   addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9922   // Step 2: re-order newly created nodes according to the ordering found in m2
9923   std::vector< std::vector<int> > intersectEdge2;
9924   BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9925   subDiv2.clear();
9926   // Step 3: compute splitMesh1D
9927   MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9928   MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9929   MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9930       idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9931   MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9932   MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9933   // deal with cells in mesh2D that are not cut but only some of their edges are
9934   MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9935   idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9936   idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9937   MCAuto<DataArrayInt> out0s;//ids in mesh2D that are impacted by the fact that some edges of \a mesh1D are part of the edges of those cells
9938   if(!idsInDesc2DToBeRefined->empty())
9939     {
9940       DataArrayInt *out0(0),*outi0(0);
9941       MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9942       MCAuto<DataArrayInt> outi0s(outi0);
9943       out0s=out0;
9944       out0s=out0s->buildUnique();
9945       out0s->sort(true);
9946     }
9947   //
9948   MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9949   MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9950   MCAuto<DataArrayInt> elts,eltsIndex;
9951   mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9952   MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9953   MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9954   if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9955     throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9956   MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9957   MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9958   if((DataArrayInt *)out0s)
9959     untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9960   std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9961   // OK all is ready to insert in ret2 mesh
9962   if(!untouchedCells->empty())
9963     {// the most easy part, cells in mesh2D not impacted at all
9964       outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9965       outMesh2DSplit.back()->setCoords(ret1->getCoords());
9966       ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9967     }
9968   if((DataArrayInt *)out0s)
9969     {// here dealing with cells in out0s but not in cellsToBeModified
9970       MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9971       const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9972       for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9973         {
9974           outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9975           ret1->setCoords(outMesh2DSplit.back()->getCoords());
9976         }
9977       int offset(ret2->getNumberOfTuples());
9978       ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9979       MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9980       partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9981       int kk(0),*ret3ptr(partOfRet3->getPointer());
9982       for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9983         {
9984           int faceId(std::abs(*it)-1);
9985           for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9986             {
9987               int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9988               if(tmp!=-1)
9989                 {
9990                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9991                     ret3ptr[2*kk]=tmp+offset;
9992                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9993                     ret3ptr[2*kk+1]=tmp+offset;
9994                 }
9995               else
9996                 {//the current edge is shared by a 2D cell that will be split just after
9997                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9998                     ret3ptr[2*kk]=-(*it2+1);
9999                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
10000                     ret3ptr[2*kk+1]=-(*it2+1);
10001                 }
10002             }
10003         }
10004       m1Desc->setCoords(ret1->getCoords());
10005       ret1NonCol->setCoords(ret1->getCoords());
10006       ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
10007       if(!outMesh2DSplit.empty())
10008         {
10009           DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
10010           for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
10011             (*itt)->setCoords(da);
10012         }
10013     }
10014   cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
10015   for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
10016     {
10017       MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
10018       idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
10019       MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
10020       MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
10021       MCAuto<DataArrayInt> partOfRet3;
10022       MCAuto<MEDCouplingUMesh> splitOfOneCell(BuildMesh2DCutFrom(eps,*it,m1Desc,partOfMesh1CuttingCur2DCell,dd1->begin()+dd2->getIJ(*it,0),dd1->begin()+dd2->getIJ((*it)+1,0),intersectEdge1,ret2->getNumberOfTuples(),partOfRet3));
10023       ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
10024       outMesh2DSplit.push_back(splitOfOneCell);
10025       for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10026         ret2->pushBackSilent(*it);
10027     }
10028   //
10029   std::size_t nbOfMeshes(outMesh2DSplit.size());
10030   std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10031   for(std::size_t i=0;i<nbOfMeshes;i++)
10032     tmp[i]=outMesh2DSplit[i];
10033   //
10034   ret1->getCoords()->setInfoOnComponents(compNames);
10035   MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10036   // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10037   ret3->rearrange(1);
10038   MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10039   for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10040     {
10041       int old2DCellId(-ret3->getIJ(*it,0)-1);
10042       MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10043       ret3->setIJ(*it,0,FindRightCandidateAmong(ret2D,candidates->begin(),candidates->end(),ret1,*it%2==0?-((*it)/2+1):(*it)/2+1,eps));// div by 2 because 2 components natively in ret3
10044     }
10045   ret3->changeValue(std::numeric_limits<int>::max(),-1);
10046   ret3->rearrange(2);
10047   //
10048   splitMesh1D=ret1.retn();
10049   splitMesh2D=ret2D.retn();
10050   cellIdInMesh2D=ret2.retn();
10051   cellIdInMesh1D=ret3.retn();
10052 }
10053
10054 /**
10055  * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10056  * (newly created) nodes corresponding to the edge intersections.
10057  * Output params:
10058  * @param[out] cr, crI connectivity of the resulting mesh
10059  * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10060  * TODO: describe input parameters
10061  */
10062 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10063                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10064                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10065                                                          const std::vector<double>& addCoords,
10066                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10067 {
10068   static const int SPACEDIM=2;
10069   const double *coo1(m1->getCoords()->getConstPointer());
10070   const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10071   int offset1(m1->getNumberOfNodes());
10072   const double *coo2(m2->getCoords()->getConstPointer());
10073   const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10074   int offset2(offset1+m2->getNumberOfNodes());
10075   int offset3(offset2+((int)addCoords.size())/2);
10076   MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10077   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10078   // Here a BBTree on 2D-cells, not on segments:
10079   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10080   int ncell1(m1->getNumberOfCells());
10081   crI.push_back(0);
10082   for(int i=0;i<ncell1;i++)
10083     {
10084       std::vector<int> candidates2;
10085       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10086       std::map<INTERP_KERNEL::Node *,int> mapp;
10087       std::map<int,INTERP_KERNEL::Node *> mappRev;
10088       INTERP_KERNEL::QuadraticPolygon pol1;
10089       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10090       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10091       // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10092       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10093       // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10094       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10095           desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10096       //
10097       std::set<INTERP_KERNEL::Edge *> edges1;// store all edges of pol1 that are NOT consumed by intersect cells. If any after iteration over candidates2 -> a part of pol1 should appear in result
10098       std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10099       INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10100       for(it1.first();!it1.finished();it1.next())
10101         edges1.insert(it1.current()->getPtr());
10102       //
10103       std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10104       std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10105       int ii=0;
10106       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10107         {
10108           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10109           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10110           // Complete mapping with elements coming from the current cell it2 in mesh2:
10111           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10112           // pol2 is the new QP in the final merged result.
10113           pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10114               pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10115         }
10116       ii=0;
10117       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10118         {
10119           INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10120           pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10121           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10122           pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10123         }
10124       // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10125       // by m2 but that we still want to keep in the final result.
10126       if(!edges1.empty())
10127         {
10128           try
10129           {
10130               INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10131           }
10132           catch(INTERP_KERNEL::Exception& e)
10133           {
10134               std::ostringstream oss; oss << "Error when computing residual of cell #" << i << " in source/m1 mesh ! Maybe the neighbours of this cell in mesh are not well connected !\n" << "The deep reason is the following : " << e.what();
10135               throw INTERP_KERNEL::Exception(oss.str());
10136           }
10137         }
10138       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10139         (*it).second->decrRef();
10140     }
10141 }
10142
10143 /**
10144  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10145  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10146  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10147  * The caller is to deal with the resulting DataArrayInt.
10148  *  \throw If the coordinate array is not set.
10149  *  \throw If the nodal connectivity of the cells is not defined.
10150  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10151  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10152  *
10153  * \sa DataArrayInt::sortEachPairToMakeALinkedList
10154  */
10155 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10156 {
10157   checkFullyDefined();
10158   if(getMeshDimension()!=1)
10159     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10160
10161   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10162   MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10163   MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10164   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10165   const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10166   const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10167   MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10168   const int * dsi(_dsi->getConstPointer());
10169   MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10170   m_points=0;
10171   if (dsii->getNumberOfTuples())
10172     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10173
10174   int nc(getNumberOfCells());
10175   MCAuto<DataArrayInt> result(DataArrayInt::New());
10176   result->alloc(nc,1);
10177
10178   // set of edges not used so far
10179   std::set<int> edgeSet;
10180   for (int i=0; i<nc; edgeSet.insert(i), i++);
10181
10182   int startSeg=0;
10183   int newIdx=0;
10184   // while we have points with only one neighbor segments
10185   do
10186     {
10187       std::list<int> linePiece;
10188       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10189       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10190         {
10191           // Fill the list forward (resp. backward) from the start segment:
10192           int activeSeg = startSeg;
10193           int prevPointId = -20;
10194           int ptId;
10195           while (!edgeSet.empty())
10196             {
10197               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10198                 {
10199                   if (direction==0)
10200                     linePiece.push_back(activeSeg);
10201                   else
10202                     linePiece.push_front(activeSeg);
10203                   edgeSet.erase(activeSeg);
10204                 }
10205
10206               int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10207               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10208               if (dsi[ptId] == 1) // hitting the end of the line
10209                 break;
10210               prevPointId = ptId;
10211               int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10212               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10213             }
10214         }
10215       // Done, save final piece into DA:
10216       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10217       newIdx += linePiece.size();
10218
10219       // identify next valid start segment (one which is not consumed)
10220       if(!edgeSet.empty())
10221         startSeg = *(edgeSet.begin());
10222     }
10223   while (!edgeSet.empty());
10224   return result.retn();
10225 }
10226
10227 /// @cond INTERNAL
10228
10229 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10230 {
10231   MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10232   std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10233   if(it==m.end())
10234     throw INTERP_KERNEL::Exception("Internal error in remapping !");
10235   int v((*it).second);
10236   if(v==forbVal0 || v==forbVal1)
10237     return ;
10238   if(std::find(isect.begin(),isect.end(),v)==isect.end())
10239     isect.push_back(v);
10240 }
10241
10242 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10243 {
10244   int sz(c.size());
10245   if(sz<=1)
10246     return false;
10247   bool presenceOfOn(false);
10248   for(int i=0;i<sz;i++)
10249     {
10250       INTERP_KERNEL::ElementaryEdge *e(c[i]);
10251       if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10252         continue ;
10253       IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10254       IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10255     }
10256   return presenceOfOn;
10257 }
10258
10259 /// @endcond
10260
10261 /**
10262  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10263  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10264  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10265  * a minimal creation of new nodes is wanted.
10266  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10267  * nodes if a SEG3 is split without information of middle.
10268  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10269  * avoid to have a non conform mesh.
10270  *
10271  * \return int - the number of new nodes created (in most of cases 0).
10272  * 
10273  * \throw If \a this is not coherent.
10274  * \throw If \a this has not spaceDim equal to 2.
10275  * \throw If \a this has not meshDim equal to 2.
10276  * \throw If some subcells needed to be split are orphan.
10277  * \sa MEDCouplingUMesh::conformize2D
10278  */
10279 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10280 {
10281   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10282     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10283   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10284   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10285     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10286   if(midOpt==0 && midOptI==0)
10287     {
10288       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10289       return 0;
10290     }
10291   else if(midOpt!=0 && midOptI!=0)
10292     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10293   else
10294     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10295 }
10296
10297 /*!
10298  * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10299  * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10300  * This method performs a conformization of \b this. So if a edge in \a this can be split into entire edges in \a this this method
10301  * will suppress such edges to use sub edges in \a this. So this method does not add nodes in \a this if merged edges are both linear (INTERP_KERNEL::NORM_SEG2).
10302  * In the other cases new nodes can be created. If any are created, they will be appended at the end of the coordinates object before the invokation of this method.
10303  * 
10304  * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10305  * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10306  *
10307  * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10308  * This method expects that all nodes in \a this are not closer than \a eps.
10309  * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10310  * 
10311  * \param [in] eps the relative error to detect merged edges.
10312  * \return DataArrayInt  * - The list of cellIds in \a this that have been subdivided. If empty, nothing changed in \a this (as if it were a const method). The array is a newly allocated array
10313  *                           that the user is expected to deal with.
10314  *
10315  * \throw If \a this is not coherent.
10316  * \throw If \a this has not spaceDim equal to 2.
10317  * \throw If \a this has not meshDim equal to 2.
10318  * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10319  */
10320 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10321 {
10322   static const int SPACEDIM=2;
10323   checkConsistencyLight();
10324   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10325     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10326   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10327   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10328   const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10329   MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10330   const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10331   int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10332   std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10333   std::vector<double> addCoo;
10334   BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10335   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10336   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10337   for(int i=0;i<nDescCell;i++)
10338     {
10339       std::vector<int> candidates;
10340       myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10341       for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10342         if(*it>i)
10343           {
10344             std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10345             INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10346                 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10347             INTERP_KERNEL::MergePoints merge;
10348             INTERP_KERNEL::QuadraticPolygon c1,c2;
10349             e1->intersectWith(e2,merge,c1,c2);
10350             e1->decrRef(); e2->decrRef();
10351             if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10352               overlapEdge[i].push_back(*it);
10353             if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10354               overlapEdge[*it].push_back(i);
10355           }
10356     }
10357   // splitting done. sort intersect point in intersectEdge.
10358   std::vector< std::vector<int> > middle(nDescCell);
10359   int nbOf2DCellsToBeSplit(0);
10360   bool middleNeedsToBeUsed(false);
10361   std::vector<bool> cells2DToTreat(nDescCell,false);
10362   for(int i=0;i<nDescCell;i++)
10363     {
10364       std::vector<int>& isect(intersectEdge[i]);
10365       int sz((int)isect.size());
10366       if(sz>1)
10367         {
10368           std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10369           INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10370           e->sortSubNodesAbs(coords,isect);
10371           e->decrRef();
10372         }
10373       if(sz!=0)
10374         {
10375           int idx0(rdi[i]),idx1(rdi[i+1]);
10376           if(idx1-idx0!=1)
10377             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10378           if(!cells2DToTreat[rd[idx0]])
10379             {
10380               cells2DToTreat[rd[idx0]]=true;
10381               nbOf2DCellsToBeSplit++;
10382             }
10383           // try to reuse at most eventual 'middle' of SEG3
10384           std::vector<int>& mid(middle[i]);
10385           mid.resize(sz+1,-1);
10386           if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10387             {
10388               middleNeedsToBeUsed=true;
10389               const std::vector<int>& candidates(overlapEdge[i]);
10390               std::vector<int> trueCandidates;
10391               for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10392                 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10393                   trueCandidates.push_back(*itc);
10394               int stNode(c[ci[i]+1]),endNode(isect[0]);
10395               for(int j=0;j<sz+1;j++)
10396                 {
10397                   for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10398                     {
10399                       int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10400                       if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10401                         { mid[j]=*itc; break; }
10402                     }
10403                   stNode=endNode;
10404                   endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10405                 }
10406             }
10407         }
10408     }
10409   MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10410   if(nbOf2DCellsToBeSplit==0)
10411     return ret.retn();
10412   //
10413   int *retPtr(ret->getPointer());
10414   for(int i=0;i<nCell;i++)
10415     if(cells2DToTreat[i])
10416       *retPtr++=i;
10417   //
10418   MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10419   DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10420   MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10421   DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10422   if(middleNeedsToBeUsed)
10423     { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10424   MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10425   int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10426   setCoords(modif->getCoords());//if nbOfNodesCreated==0 modif and this have the same coordinates pointer so this line has no effect. But for quadratic cases this line is important.
10427   setPartOfMySelf(ret->begin(),ret->end(),*modif);
10428   {
10429     bool areNodesMerged; int newNbOfNodes;
10430     if(nbOfNodesCreated!=0)
10431       MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10432   }
10433   return ret.retn();
10434 }
10435
10436 /*!
10437  * This non const method works on 2D mesh. This method scans every cell in \a this and look if each edge constituting this cell is not mergeable with neighbors edges of that cell.
10438  * If yes, the cell is "repaired" to minimize at most its number of edges. So this method do not change the overall shape of cells in \a this (with eps precision).
10439  * This method do not take care of shared edges between cells, so this method can lead to a non conform mesh (\a this). If a conform mesh is required you're expected
10440  * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10441  * This method works on any 2D geometric types of cell (even static one). If a cell is touched its type becomes dynamic automaticaly. For 2D "repaired" quadratic cells
10442  * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10443  *
10444  * If the returned array is empty it means that nothing has changed in \a this (as if it were a const method). If the array is not empty the connectivity of \a this is modified
10445  * using new instance, idem for coordinates.
10446  *
10447  * If \a this is constituted by only linear 2D cells, this method is close to the computation of the convex hull of each cells in \a this.
10448  * 
10449  * \return DataArrayInt  * - The list of cellIds in \a this that have at least one edge colinearized.
10450  *
10451  * \throw If \a this is not coherent.
10452  * \throw If \a this has not spaceDim equal to 2.
10453  * \throw If \a this has not meshDim equal to 2.
10454  * 
10455  * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10456  */
10457 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10458 {
10459   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10460   checkConsistencyLight();
10461   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10462     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10463   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10464   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10465   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10466   const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10467   MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10468   MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10469   const double *coords(_coords->begin());
10470   int *newciptr(newci->getPointer());
10471   for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10472     {
10473       if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10474         ret->pushBackSilent(i);
10475       newciptr[1]=newc->getNumberOfTuples();
10476     }
10477   //
10478   if(ret->empty())
10479     return ret.retn();
10480   if(!appendedCoords->empty())
10481     {
10482       appendedCoords->rearrange(2);
10483       MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10484       //non const part
10485       setCoords(newCoords);
10486     }
10487   //non const part
10488   setConnectivity(newc,newci,true);
10489   return ret.retn();
10490 }
10491
10492 /*!
10493  * \param [out] intersectEdge1 - for each cell in \a m1Desc returns the result of the split. The result is given using pair of int given resp start and stop.
10494  *                               So for all edge \a i in \a m1Desc \a  intersectEdge1[i] is of length 2*n where n is the number of sub edges.
10495  *                               And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10496  * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10497  * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10498  * \param [out] addCoo - nodes to be append at the end
10499  * \param [out] mergedNodes - gives all pair of nodes of \a m2Desc that have same location than some nodes in \a m1Desc. key is id in \a m2Desc offseted and value is id in \a m1Desc.
10500  */
10501 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10502                                          std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2, std::vector<double>& addCoo, std::map<int,int>& mergedNodes)
10503 {
10504   static const int SPACEDIM=2;
10505   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10506   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10507   const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10508   // Build BB tree of all edges in the tool mesh (second mesh)
10509   MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10510   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10511   int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10512   intersectEdge1.resize(nDescCell1);
10513   colinear2.resize(nDescCell2);
10514   subDiv2.resize(nDescCell2);
10515   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10516
10517   std::vector<int> candidates1(1);
10518   int offset1(m1Desc->getNumberOfNodes());
10519   int offset2(offset1+m2Desc->getNumberOfNodes());
10520   for(int i=0;i<nDescCell1;i++)  // for all edges in the first mesh
10521     {
10522       std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10523       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10524       if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10525         {
10526           std::map<INTERP_KERNEL::Node *,int> map1,map2;
10527           // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10528           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10529           candidates1[0]=i;
10530           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10531           // This following part is to avoid that some removed nodes (for example due to a merge between pol1 and pol2) are replaced by a newly created one
10532           // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10533           std::set<INTERP_KERNEL::Node *> nodes;
10534           pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10535           std::size_t szz(nodes.size());
10536           std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10537           std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10538           for(std::size_t iii=0;iii<szz;iii++,itt++)
10539             { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10540           // end of protection
10541           // Performs egde cutting:
10542           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10543           delete pol2;
10544           delete pol1;
10545         }
10546       else
10547         // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10548         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10549     }
10550 }
10551
10552 /*!
10553  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10554  * It builds the descending connectivity of the two meshes, and then using a binary tree
10555  * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10556  * Documentation about parameters  colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10557  */
10558 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10559                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10560                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10561                                                    std::vector<double>& addCoo,
10562                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10563 {
10564   // Build desc connectivity
10565   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10566   desc2=DataArrayInt::New();
10567   descIndx2=DataArrayInt::New();
10568   revDesc2=DataArrayInt::New();
10569   revDescIndx2=DataArrayInt::New();
10570   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10571   MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10572   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10573   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10574   MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10575   std::map<int,int> notUsedMap;
10576   Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10577   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10578   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10579 }
10580
10581 /*!
10582  * This method performs the 2nd step of Partition of 2D mesh.
10583  * This method has 4 inputs :
10584  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10585  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10586  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10587  * The aim of this method is to sort the splitting nodes, if any, and to put them in 'intersectEdge' output parameter based on edges of mesh 'm2'
10588  * Nodes end up lying consecutively on a cutted edge.
10589  * \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.
10590  * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10591  * \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.
10592  * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10593  * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10594  */
10595 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10596                                            const std::vector<double>& addCoo,
10597                                            const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10598 {
10599   int offset1=m1->getNumberOfNodes();
10600   int ncell=m2->getNumberOfCells();
10601   const int *c=m2->getNodalConnectivity()->getConstPointer();
10602   const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10603   const double *coo=m2->getCoords()->getConstPointer();
10604   const double *cooBis=m1->getCoords()->getConstPointer();
10605   int offset2=offset1+m2->getNumberOfNodes();
10606   intersectEdge.resize(ncell);
10607   for(int i=0;i<ncell;i++,cI++)
10608     {
10609       const std::vector<int>& divs=subDiv[i];
10610       int nnode=cI[1]-cI[0]-1;
10611       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10612       std::map<INTERP_KERNEL::Node *, int> mapp22;
10613       for(int j=0;j<nnode;j++)
10614         {
10615           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10616           int nnid=c[(*cI)+j+1];
10617           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10618           mapp22[nn]=nnid+offset1;
10619         }
10620       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10621       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10622         ((*it).second.first)->decrRef();
10623       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10624       std::map<INTERP_KERNEL::Node *,int> mapp3;
10625       for(std::size_t j=0;j<divs.size();j++)
10626         {
10627           int id=divs[j];
10628           INTERP_KERNEL::Node *tmp=0;
10629           if(id<offset1)
10630             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10631           else if(id<offset2)
10632             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10633           else
10634             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10635           addNodes[j]=tmp;
10636           mapp3[tmp]=id;
10637         }
10638       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10639       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10640         (*it)->decrRef();
10641       e->decrRef();
10642     }
10643 }
10644
10645 /*!
10646  * 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).
10647  * 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
10648  * with a plane. The result will be put in 'cut3DSuf' out parameter.
10649  * \param [in] cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10650  * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10651  * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10652  * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10653  * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10654  * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10655  * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10656  * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10657  * \param [out] cut3DSuf input/output param.
10658  */
10659 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10660                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
10661                                                    const int *desc, const int *descIndx, 
10662                                                    std::vector< std::pair<int,int> >& cut3DSurf)
10663 {
10664   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10665   int nbOf3DSurfCell=(int)cut3DSurf.size();
10666   for(int i=0;i<nbOf3DSurfCell;i++)
10667     {
10668       std::vector<int> res;
10669       int offset=descIndx[i];
10670       int nbOfSeg=descIndx[i+1]-offset;
10671       for(int j=0;j<nbOfSeg;j++)
10672         {
10673           int edgeId=desc[offset+j];
10674           int status=cut3DCurve[edgeId];
10675           if(status!=-2)
10676             {
10677               if(status>-1)
10678                 res.push_back(status);
10679               else
10680                 {
10681                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10682                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10683                 }
10684             }
10685         }
10686       switch(res.size())
10687       {
10688         case 2:
10689           {
10690             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10691             break;
10692           }
10693         case 1:
10694         case 0:
10695           {
10696             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10697             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10698             if(res.size()==2)
10699               {
10700                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10701               }
10702             else
10703               {
10704                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10705               }
10706             break;
10707           }
10708         default:
10709           {// case when plane is on a multi colinear edge of a polyhedron
10710             if((int)res.size()==2*nbOfSeg)
10711               {
10712                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10713               }
10714             else
10715               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10716           }
10717       }
10718     }
10719 }
10720
10721 /*!
10722  * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10723  * 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).
10724  * 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
10725  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10726  * \param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10727  * \param desc is the descending connectivity 3D->3DSurf
10728  * \param descIndx is the descending connectivity index 3D->3DSurf
10729  */
10730 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10731                                                   const int *desc, const int *descIndx,
10732                                                   DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10733 {
10734   checkFullyDefined();
10735   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10736     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10737   const int *nodal3D=_nodal_connec->getConstPointer();
10738   const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10739   int nbOfCells=getNumberOfCells();
10740   for(int i=0;i<nbOfCells;i++)
10741     {
10742       std::map<int, std::set<int> > m;
10743       int offset=descIndx[i];
10744       int nbOfFaces=descIndx[i+1]-offset;
10745       int start=-1;
10746       int end=-1;
10747       for(int j=0;j<nbOfFaces;j++)
10748         {
10749           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10750           if(p.first!=-1 && p.second!=-1)
10751             {
10752               if(p.first!=-2)
10753                 {
10754                   start=p.first; end=p.second;
10755                   m[p.first].insert(p.second);
10756                   m[p.second].insert(p.first);
10757                 }
10758               else
10759                 {
10760                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10761                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10762                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10763                   INTERP_KERNEL::NormalizedCellType cmsId;
10764                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10765                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
10766                   for(unsigned k=0;k<nbOfNodesSon;k++)
10767                     {
10768                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10769                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10770                     }
10771                 }
10772             }
10773         }
10774       if(m.empty())
10775         continue;
10776       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10777       int prev=end;
10778       while(end!=start)
10779         {
10780           std::map<int, std::set<int> >::const_iterator it=m.find(start);
10781           const std::set<int>& s=(*it).second;
10782           std::set<int> s2; s2.insert(prev);
10783           std::set<int> s3;
10784           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10785           if(s3.size()==1)
10786             {
10787               int val=*s3.begin();
10788               conn.push_back(start);
10789               prev=start;
10790               start=val;
10791             }
10792           else
10793             start=end;
10794         }
10795       conn.push_back(end);
10796       if(conn.size()>3)
10797         {
10798           nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10799           nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10800           cellIds->pushBackSilent(i);
10801         }
10802     }
10803 }
10804
10805 /*!
10806  * 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
10807  * 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
10808  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10809  * 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
10810  * 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.
10811  * 
10812  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10813  */
10814 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10815 {
10816   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10817   if(sz>=4)
10818     {
10819       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10820       if(cm.getDimension()==2)
10821         {
10822           const int *node=nodalConnBg+1;
10823           int startNode=*node++;
10824           double refX=coords[2*startNode];
10825           for(;node!=nodalConnEnd;node++)
10826             {
10827               if(coords[2*(*node)]<refX)
10828                 {
10829                   startNode=*node;
10830                   refX=coords[2*startNode];
10831                 }
10832             }
10833           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10834           refX=1e300;
10835           double tmp1;
10836           double tmp2[2];
10837           double angle0=-M_PI/2;
10838           //
10839           int nextNode=-1;
10840           int prevNode=-1;
10841           double resRef;
10842           double angleNext=0.;
10843           while(nextNode!=startNode)
10844             {
10845               nextNode=-1;
10846               resRef=1e300;
10847               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10848                 {
10849                   if(*node!=tmpOut.back() && *node!=prevNode)
10850                     {
10851                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10852                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10853                       double res;
10854                       if(angleM<=angle0)
10855                         res=angle0-angleM;
10856                       else
10857                         res=angle0-angleM+2.*M_PI;
10858                       if(res<resRef)
10859                         {
10860                           nextNode=*node;
10861                           resRef=res;
10862                           angleNext=angleM;
10863                         }
10864                     }
10865                 }
10866               if(nextNode!=startNode)
10867                 {
10868                   angle0=angleNext-M_PI;
10869                   if(angle0<-M_PI)
10870                     angle0+=2*M_PI;
10871                   prevNode=tmpOut.back();
10872                   tmpOut.push_back(nextNode);
10873                 }
10874             }
10875           std::vector<int> tmp3(2*(sz-1));
10876           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10877           std::copy(nodalConnBg+1,nodalConnEnd,it);
10878           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10879             {
10880               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10881               return false;
10882             }
10883           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10884             {
10885               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10886               return false;
10887             }
10888           else
10889             {
10890               nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10891               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10892               return true;
10893             }
10894         }
10895       else
10896         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10897     }
10898   else
10899     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10900 }
10901
10902 /*!
10903  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10904  * 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.
10905  * 
10906  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10907  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10908  * \param [in,out] arr array in which the remove operation will be done.
10909  * \param [in,out] arrIndx array in the remove operation will modify
10910  * \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])
10911  * \return true if \b arr and \b arrIndx have been modified, false if not.
10912  */
10913 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10914 {
10915   if(!arrIndx || !arr)
10916     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10917   if(offsetForRemoval<0)
10918     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10919   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10920   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10921   int *arrIPtr=arrIndx->getPointer();
10922   *arrIPtr++=0;
10923   int previousArrI=0;
10924   const int *arrPtr=arr->getConstPointer();
10925   std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10926   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10927     {
10928       if(*arrIPtr-previousArrI>offsetForRemoval)
10929         {
10930           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10931             {
10932               if(s.find(*work)==s.end())
10933                 arrOut.push_back(*work);
10934             }
10935         }
10936       previousArrI=*arrIPtr;
10937       *arrIPtr=(int)arrOut.size();
10938     }
10939   if(arr->getNumberOfTuples()==(int)arrOut.size())
10940     return false;
10941   arr->alloc((int)arrOut.size(),1);
10942   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10943   return true;
10944 }
10945
10946 /*!
10947  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10948  * (\ref numbering-indirect).
10949  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10950  * The selection of extraction is done standardly in new2old format.
10951  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10952  *
10953  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10954  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10955  * \param [in] arrIn arr origin array from which the extraction will be done.
10956  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10957  * \param [out] arrOut the resulting array
10958  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10959  * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10960  */
10961 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10962                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10963 {
10964   if(!arrIn || !arrIndxIn)
10965     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10966   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10967   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10968     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10969   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10970   const int *arrInPtr=arrIn->getConstPointer();
10971   const int *arrIndxPtr=arrIndxIn->getConstPointer();
10972   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10973   if(nbOfGrps<0)
10974     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10975   int maxSizeOfArr=arrIn->getNumberOfTuples();
10976   MCAuto<DataArrayInt> arro=DataArrayInt::New();
10977   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10978   arrIo->alloc((int)(sz+1),1);
10979   const int *idsIt=idsOfSelectBg;
10980   int *work=arrIo->getPointer();
10981   *work++=0;
10982   int lgth=0;
10983   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10984     {
10985       if(*idsIt>=0 && *idsIt<nbOfGrps)
10986         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10987       else
10988         {
10989           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10990           throw INTERP_KERNEL::Exception(oss.str());
10991         }
10992       if(lgth>=work[-1])
10993         *work=lgth;
10994       else
10995         {
10996           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10997           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10998           throw INTERP_KERNEL::Exception(oss.str());
10999         }
11000     }
11001   arro->alloc(lgth,1);
11002   work=arro->getPointer();
11003   idsIt=idsOfSelectBg;
11004   for(std::size_t i=0;i<sz;i++,idsIt++)
11005     {
11006       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
11007         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
11008       else
11009         {
11010           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
11011           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11012           throw INTERP_KERNEL::Exception(oss.str());
11013         }
11014     }
11015   arrOut=arro.retn();
11016   arrIndexOut=arrIo.retn();
11017 }
11018
11019 /*!
11020  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
11021  * (\ref numbering-indirect).
11022  * This method returns the result of the extraction ( specified by a set of ids with a slice given by \a idsOfSelectStart, \a idsOfSelectStop and \a idsOfSelectStep ).
11023  * The selection of extraction is done standardly in new2old format.
11024  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11025  *
11026  * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11027  * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11028  * \param [in] idsOfSelectStep
11029  * \param [in] arrIn arr origin array from which the extraction will be done.
11030  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11031  * \param [out] arrOut the resulting array
11032  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11033  * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11034  */
11035 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11036                                                  DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11037 {
11038   if(!arrIn || !arrIndxIn)
11039     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11040   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11041   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11042     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11043   int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11044   const int *arrInPtr=arrIn->getConstPointer();
11045   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11046   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11047   if(nbOfGrps<0)
11048     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11049   int maxSizeOfArr=arrIn->getNumberOfTuples();
11050   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11051   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11052   arrIo->alloc((int)(sz+1),1);
11053   int idsIt=idsOfSelectStart;
11054   int *work=arrIo->getPointer();
11055   *work++=0;
11056   int lgth=0;
11057   for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11058     {
11059       if(idsIt>=0 && idsIt<nbOfGrps)
11060         lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11061       else
11062         {
11063           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11064           throw INTERP_KERNEL::Exception(oss.str());
11065         }
11066       if(lgth>=work[-1])
11067         *work=lgth;
11068       else
11069         {
11070           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11071           oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11072           throw INTERP_KERNEL::Exception(oss.str());
11073         }
11074     }
11075   arro->alloc(lgth,1);
11076   work=arro->getPointer();
11077   idsIt=idsOfSelectStart;
11078   for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11079     {
11080       if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11081         work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11082       else
11083         {
11084           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11085           oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11086           throw INTERP_KERNEL::Exception(oss.str());
11087         }
11088     }
11089   arrOut=arro.retn();
11090   arrIndexOut=arrIo.retn();
11091 }
11092
11093 /*!
11094  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11095  * 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
11096  * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11097  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11098  *
11099  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11100  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11101  * \param [in] arrIn arr origin array from which the extraction will be done.
11102  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11103  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11104  * \param [in] srcArrIndex index array of \b srcArr
11105  * \param [out] arrOut the resulting array
11106  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11107  * 
11108  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11109  */
11110 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11111                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11112                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11113 {
11114   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11115     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11116   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11117   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11118   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11119   std::vector<bool> v(nbOfTuples,true);
11120   int offset=0;
11121   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11122   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11123   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11124     {
11125       if(*it>=0 && *it<nbOfTuples)
11126         {
11127           v[*it]=false;
11128           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11129         }
11130       else
11131         {
11132           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11133           throw INTERP_KERNEL::Exception(oss.str());
11134         }
11135     }
11136   srcArrIndexPtr=srcArrIndex->getConstPointer();
11137   arrIo->alloc(nbOfTuples+1,1);
11138   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11139   const int *arrInPtr=arrIn->getConstPointer();
11140   const int *srcArrPtr=srcArr->getConstPointer();
11141   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11142   int *arroPtr=arro->getPointer();
11143   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11144     {
11145       if(v[ii])
11146         {
11147           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11148           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11149         }
11150       else
11151         {
11152           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11153           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11154           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11155         }
11156     }
11157   arrOut=arro.retn();
11158   arrIndexOut=arrIo.retn();
11159 }
11160
11161 /*!
11162  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11163  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11164  *
11165  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11166  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11167  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11168  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11169  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11170  * \param [in] srcArrIndex index array of \b srcArr
11171  * 
11172  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11173  */
11174 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11175                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11176 {
11177   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11178     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11179   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11180   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11181   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11182   int *arrInOutPtr=arrInOut->getPointer();
11183   const int *srcArrPtr=srcArr->getConstPointer();
11184   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11185     {
11186       if(*it>=0 && *it<nbOfTuples)
11187         {
11188           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11189             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11190           else
11191             {
11192               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] !";
11193               throw INTERP_KERNEL::Exception(oss.str());
11194             }
11195         }
11196       else
11197         {
11198           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11199           throw INTERP_KERNEL::Exception(oss.str());
11200         }
11201     }
11202 }
11203
11204 /*!
11205  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11206  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11207  * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 looking at arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11208  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11209  * A negative value in \b arrIn means that it is ignored.
11210  * This method is useful 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.
11211  * 
11212  * \param [in] arrIn arr origin array from which the extraction will be done.
11213  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11214  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11215  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11216  */
11217 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11218 {
11219   int seed=0,nbOfDepthPeelingPerformed=0;
11220   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11221 }
11222
11223 /*!
11224  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11225  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11226  * 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]].
11227  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11228  * A negative value in \b arrIn means that it is ignored.
11229  * This method is useful 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.
11230  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11231  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11232  * \param [in] arrIn arr origin array from which the extraction will be done.
11233  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11234  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11235  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11236  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11237  * \sa MEDCouplingUMesh::partitionBySpreadZone
11238  */
11239 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11240 {
11241   nbOfDepthPeelingPerformed=0;
11242   if(!arrIndxIn)
11243     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11244   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11245   if(nbOfTuples<=0)
11246     {
11247       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11248       return ret;
11249     }
11250   //
11251   std::vector<bool> fetched(nbOfTuples,false);
11252   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11253 }
11254
11255 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11256 {
11257   nbOfDepthPeelingPerformed=0;
11258   if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11259     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11260   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11261   std::vector<bool> fetched2(nbOfTuples,false);
11262   int i=0;
11263   for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11264     {
11265       if(*seedElt>=0 && *seedElt<nbOfTuples)
11266         { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11267       else
11268         { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str()); }
11269     }
11270   const int *arrInPtr=arrIn->getConstPointer();
11271   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11272   int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11273   std::vector<int> idsToFetch1(seedBg,seedEnd);
11274   std::vector<int> idsToFetch2;
11275   std::vector<int> *idsToFetch=&idsToFetch1;
11276   std::vector<int> *idsToFetchOther=&idsToFetch2;
11277   while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11278     {
11279       for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11280         for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11281           if(!fetched[*it2])
11282             { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11283       std::swap(idsToFetch,idsToFetchOther);
11284       idsToFetchOther->clear();
11285       nbOfDepthPeelingPerformed++;
11286     }
11287   int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11288   i=0;
11289   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11290   int *retPtr=ret->getPointer();
11291   for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11292     if(*it)
11293       *retPtr++=i;
11294   return ret.retn();
11295 }
11296
11297 /*!
11298  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11299  * 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
11300  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11301  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11302  *
11303  * \param [in] start begin of set of ids of the input extraction (included)
11304  * \param [in] end end of set of ids of the input extraction (excluded)
11305  * \param [in] step step of the set of ids in range mode.
11306  * \param [in] arrIn arr origin array from which the extraction will be done.
11307  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11308  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11309  * \param [in] srcArrIndex index array of \b srcArr
11310  * \param [out] arrOut the resulting array
11311  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11312  * 
11313  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11314  */
11315 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11316                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11317                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11318 {
11319   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11320     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11321   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11322   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11323   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11324   int offset=0;
11325   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11326   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11327   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11328   int it=start;
11329   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11330     {
11331       if(it>=0 && it<nbOfTuples)
11332         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11333       else
11334         {
11335           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11336           throw INTERP_KERNEL::Exception(oss.str());
11337         }
11338     }
11339   srcArrIndexPtr=srcArrIndex->getConstPointer();
11340   arrIo->alloc(nbOfTuples+1,1);
11341   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11342   const int *arrInPtr=arrIn->getConstPointer();
11343   const int *srcArrPtr=srcArr->getConstPointer();
11344   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11345   int *arroPtr=arro->getPointer();
11346   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11347     {
11348       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11349       if(pos<0)
11350         {
11351           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11352           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11353         }
11354       else
11355         {
11356           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11357           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11358         }
11359     }
11360   arrOut=arro.retn();
11361   arrIndexOut=arrIo.retn();
11362 }
11363
11364 /*!
11365  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11366  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11367  *
11368  * \param [in] start begin of set of ids of the input extraction (included)
11369  * \param [in] end end of set of ids of the input extraction (excluded)
11370  * \param [in] step step of the set of ids in range mode.
11371  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11372  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11373  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11374  * \param [in] srcArrIndex index array of \b srcArr
11375  * 
11376  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11377  */
11378 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11379                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11380 {
11381   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11382     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11383   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11384   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11385   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11386   int *arrInOutPtr=arrInOut->getPointer();
11387   const int *srcArrPtr=srcArr->getConstPointer();
11388   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11389   int it=start;
11390   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11391     {
11392       if(it>=0 && it<nbOfTuples)
11393         {
11394           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11395             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11396           else
11397             {
11398               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11399               throw INTERP_KERNEL::Exception(oss.str());
11400             }
11401         }
11402       else
11403         {
11404           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11405           throw INTERP_KERNEL::Exception(oss.str());
11406         }
11407     }
11408 }
11409
11410 /*!
11411  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11412  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11413  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11414  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11415  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11416  * 
11417  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11418  */
11419 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11420 {
11421   checkFullyDefined();
11422   int mdim=getMeshDimension();
11423   int spaceDim=getSpaceDimension();
11424   if(mdim!=spaceDim)
11425     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11426   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11427   std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11428   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11429   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11430   ret->setCoords(getCoords());
11431   ret->allocateCells((int)partition.size());
11432   //
11433   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11434     {
11435       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11436       MCAuto<DataArrayInt> cell;
11437       switch(mdim)
11438       {
11439         case 2:
11440           cell=tmp->buildUnionOf2DMesh();
11441           break;
11442         case 3:
11443           cell=tmp->buildUnionOf3DMesh();
11444           break;
11445         default:
11446           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11447       }
11448
11449       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11450     }
11451   //
11452   ret->finishInsertingCells();
11453   return ret.retn();
11454 }
11455
11456 /*!
11457  * This method partitions \b this into contiguous zone.
11458  * This method only needs a well defined connectivity. Coordinates are not considered here.
11459  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11460  */
11461 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11462 {
11463   int nbOfCellsCur=getNumberOfCells();
11464   std::vector<DataArrayInt *> ret;
11465   if(nbOfCellsCur<=0)
11466     return ret;
11467   DataArrayInt *neigh=0,*neighI=0;
11468   computeNeighborsOfCells(neigh,neighI);
11469   MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11470   std::vector<bool> fetchedCells(nbOfCellsCur,false);
11471   std::vector< MCAuto<DataArrayInt> > ret2;
11472   int seed=0;
11473   while(seed<nbOfCellsCur)
11474     {
11475       int nbOfPeelPerformed=0;
11476       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11477       seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11478     }
11479   for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11480     ret.push_back((*it).retn());
11481   return ret;
11482 }
11483
11484 /*!
11485  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11486  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11487  *
11488  * \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.
11489  * \return a newly allocated DataArrayInt to be managed by the caller.
11490  * \throw In case of \a code has not the right format (typically of size 3*n)
11491  */
11492 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11493 {
11494   MCAuto<DataArrayInt> ret=DataArrayInt::New();
11495   std::size_t nb=code.size()/3;
11496   if(code.size()%3!=0)
11497     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11498   ret->alloc((int)nb,2);
11499   int *retPtr=ret->getPointer();
11500   for(std::size_t i=0;i<nb;i++,retPtr+=2)
11501     {
11502       retPtr[0]=code[3*i+2];
11503       retPtr[1]=code[3*i+2]+code[3*i+1];
11504     }
11505   return ret.retn();
11506 }
11507
11508 /*!
11509  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11510  * All cells in \a this are expected to be linear 3D cells.
11511  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11512  * It leads to an increase to number of cells.
11513  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11514  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints 
11515  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11516  *
11517  * \param [in] policy - the policy of splitting that must be in (PLANAR_FACE_5, PLANAR_FACE_6, GENERAL_24, GENERAL_48). The policy will be used only for INTERP_KERNEL::NORM_HEXA8 cells.
11518  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11519  * \param [out] nbOfAdditionalPoints - number of nodes added to \c this->_coords. If > 0 a new coordinates object will be constructed result of the aggregation of the old one and the new points added. 
11520  * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11521  *          an id of old cell producing it. The caller is to delete this array using
11522  *         decrRef() as it is no more needed.
11523  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11524  *
11525  * \warning This method operates on each cells in this independantly ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
11526  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11527  * 
11528  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11529  * \throw If \a this is not fully constituted with linear 3D cells.
11530  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11531  */
11532 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11533 {
11534   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11535   checkConnectivityFullyDefined();
11536   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11537     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11538   int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11539   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11540   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11541   int *retPt(ret->getPointer());
11542   MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11543   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11544   const int *oldc(_nodal_connec->begin());
11545   const int *oldci(_nodal_connec_index->begin());
11546   const double *coords(_coords->begin());
11547   for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11548     {
11549       std::vector<int> a; std::vector<double> b;
11550       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11551       std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11552       const int *aa(&a[0]);
11553       if(!b.empty())
11554         {
11555           for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11556             if(*it<0)
11557               *it=(-(*(it))-1+nbNodes);
11558           addPts->insertAtTheEnd(b.begin(),b.end());
11559           nbNodes+=(int)b.size()/3;
11560         }
11561       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11562         newConn->insertAtTheEnd(aa,aa+4);
11563     }
11564   if(!addPts->empty())
11565     {
11566       addPts->rearrange(3);
11567       nbOfAdditionalPoints=addPts->getNumberOfTuples();
11568       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11569       ret0->setCoords(addPts);
11570     }
11571   else
11572     {
11573       nbOfAdditionalPoints=0;
11574       ret0->setCoords(getCoords());
11575     }
11576   ret0->setNodalConnectivity(newConn);
11577   //
11578   ret->computeOffsetsFull();
11579   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11580   return ret0.retn();
11581 }
11582
11583 /*!
11584  * It is the linear part of MEDCouplingUMesh::split2DCells. Here no additionnal nodes will be added in \b this. So coordinates pointer remain unchanged (is not even touch). 
11585  *
11586  * \sa MEDCouplingUMesh::split2DCells
11587  */
11588 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11589 {
11590   checkConnectivityFullyDefined();
11591   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11592   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11593   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11594   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11595   int prevPosOfCi(ciPtr[0]);
11596   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11597     {
11598       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11599       *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11600       for(int j=0;j<sz;j++)
11601         {
11602           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11603           for(int k=0;k<sz2;k++)
11604             *cPtr++=subPtr[offset2+k];
11605           if(j!=sz-1)
11606             *cPtr++=oldConn[prevPosOfCi+j+2];
11607           deltaSz+=sz2;
11608         }
11609       prevPosOfCi=ciPtr[1];
11610       ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11611     }
11612   if(c->end()!=cPtr)
11613     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11614   _nodal_connec->decrRef();
11615   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11616 }
11617
11618 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11619 {
11620   if(id!=-1)
11621     return id;
11622   else
11623     {
11624       int ret(nodesCnter++);
11625       double newPt[2];
11626       e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11627       addCoo.insertAtTheEnd(newPt,newPt+2);
11628       return ret;
11629     }
11630 }
11631
11632 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11633 {
11634   if(id!=-1)
11635     return id;
11636   else
11637     {
11638       int ret(nodesCnter++);
11639       double newPt[2];
11640       e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11641       addCoo.insertAtTheEnd(newPt,newPt+2);
11642       return ret;
11643     }
11644 }
11645
11646
11647 /// @cond INTERNAL
11648
11649 void EnterTheResultOf2DCellFirst(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11650 {
11651   int tmp[3];
11652   int trueStart(start>=0?start:nbOfEdges+start);
11653   tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11654   newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11655   if(linOrArc)
11656     {
11657       if(stp-start>1)
11658         {
11659           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11660           InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11661           middles.push_back(tmp3+offset);
11662         }
11663       else
11664         middles.push_back(connBg[trueStart+nbOfEdges]);
11665     }
11666 }
11667
11668 void EnterTheResultOf2DCellMiddle(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11669 {
11670   int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11671   newConnOfCell->pushBackSilent(tmpEnd);
11672   if(linOrArc)
11673     {
11674       if(stp-start>1)
11675         {
11676           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11677           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11678           middles.push_back(tmp3+offset);
11679         }
11680       else
11681         middles.push_back(connBg[start+nbOfEdges]);
11682     }
11683 }
11684
11685 void EnterTheResultOf2DCellEnd(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11686 {
11687   // only the quadratic point to deal with:
11688   if(linOrArc)
11689     {
11690       if(stp-start>1)
11691         {
11692           int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11693           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11694           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11695           middles.push_back(tmp3+offset);
11696         }
11697       else
11698         middles.push_back(connBg[start+nbOfEdges]);
11699     }
11700 }
11701
11702 /// @endcond
11703
11704 /*!
11705  * Returns true if a colinearization has been found in the given cell. If false is returned the content pushed in \a newConnOfCell is equal to [ \a connBg , \a connEnd ) .
11706  * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11707  */
11708 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11709 {
11710   std::size_t sz(std::distance(connBg,connEnd));
11711   if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11712     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11713   sz--;
11714   INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11715   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11716   unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11717   unsigned nbOfHit(0); // number of fusions operated
11718   int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11719   const unsigned int maxNbOfHit = cm.isQuadratic() ? nbs-2 : nbs-3;  // a quad cell is authorized to end up with only two edges, a linear one has to keep 3 at least
11720   INTERP_KERNEL::NormalizedCellType typeOfSon;
11721   std::vector<int> middles;
11722   bool ret(false);
11723   for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11724     {
11725       cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11726       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11727       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11728       posEndElt = posBaseElt+1;
11729
11730       // Look backward first: are the final edges of the cells colinear with the first ones?
11731       // This initializes posBaseElt.
11732       if(nbOfTurn==0)
11733         {
11734           for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11735             {
11736               cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11737               INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11738               INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11739               bool isColinear=eint->areColinears();
11740               if(isColinear)
11741                 {
11742                   nbOfHit++;
11743                   posBaseElt--;
11744                   ret=true;
11745                 }
11746               delete eint;
11747               eCand->decrRef();
11748               if(!isColinear)
11749                 break;
11750             }
11751         }
11752       // Now move forward:
11753       const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt);  // the first element to be inspected going forward
11754       for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++)  // 2nd condition is to avoid ending with a cell wih one single edge
11755         {
11756           cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11757           INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11758           INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11759           bool isColinear(eint->areColinears());
11760           if(isColinear)
11761             {
11762               nbOfHit++;
11763               posEndElt++;
11764               ret=true;
11765             }
11766           delete eint;
11767           eCand->decrRef();
11768           if(!isColinear)
11769               break;
11770         }
11771       //push [posBaseElt,posEndElt) in newConnOfCell using e
11772       // The if clauses below are (volontary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its begining!
11773       if(nbOfTurn==0)
11774         // at the begining of the connectivity (insert type)
11775         EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11776       else if((nbOfHit+nbOfTurn) != (nbs-1))
11777         // in the middle
11778         EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11779       if ((nbOfHit+nbOfTurn) == (nbs-1))
11780         // at the end (only quad points to deal with)
11781         EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11782       posBaseElt=posEndElt;
11783       e->decrRef();
11784     }
11785   if(!middles.empty())
11786     newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11787   return ret;
11788 }
11789
11790 /*!
11791  * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11792  *
11793  * \return  int - the number of new nodes created.
11794  * \sa MEDCouplingUMesh::split2DCells
11795  */
11796 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11797 {
11798   checkConsistencyLight();
11799   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11800   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11801   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11802   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11803   const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11804   const double *oldCoordsPtr(getCoords()->begin());
11805   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11806   int prevPosOfCi(ciPtr[0]);
11807   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11808     {
11809       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11810       for(int j=0;j<sz;j++)
11811         { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11812       *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11813       for(int j=0;j<sz;j++)//loop over subedges of oldConn
11814         {
11815           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11816           if(sz2==0)
11817             {
11818               if(j<sz-1)
11819                 cPtr[1]=oldConn[prevPosOfCi+2+j];
11820               cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11821               continue;
11822             }
11823           std::vector<INTERP_KERNEL::Node *> ns(3);
11824           ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11825           ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11826           ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11827           MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11828           for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11829             {
11830               cPtr[1]=subPtr[offset2+k];
11831               cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11832             }
11833           int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11834           if(j!=sz-1)
11835             { cPtr[1]=tmpEnd; }
11836           cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11837         }
11838       prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11839       ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11840     }
11841   if(c->end()!=cPtr)
11842     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11843   _nodal_connec->decrRef();
11844   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11845   addCoo->rearrange(2);
11846   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11847   setCoords(coo);
11848   return addCoo->getNumberOfTuples();
11849 }
11850
11851 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11852 {
11853   if(nodalConnec && nodalConnecIndex)
11854     {
11855       types.clear();
11856       const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11857       int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11858       if(nbOfElem>0)
11859         for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11860           types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11861     }
11862 }
11863
11864 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11865     _own_cell(true),_cell_id(-1),_nb_cell(0)
11866 {
11867   if(mesh)
11868     {
11869       mesh->incrRef();
11870       _nb_cell=mesh->getNumberOfCells();
11871     }
11872 }
11873
11874 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11875 {
11876   if(_mesh)
11877     _mesh->decrRef();
11878   if(_own_cell)
11879     delete _cell;
11880 }
11881
11882 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11883     _own_cell(false),_cell_id(bg-1),
11884     _nb_cell(end)
11885 {
11886   if(mesh)
11887     mesh->incrRef();
11888 }
11889
11890 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11891 {
11892   _cell_id++;
11893   if(_cell_id<_nb_cell)
11894     {
11895       _cell->next();
11896       return _cell;
11897     }
11898   else
11899     return 0;
11900 }
11901
11902 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11903 {
11904   if(_mesh)
11905     _mesh->incrRef();
11906 }
11907
11908 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11909 {
11910   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11911 }
11912
11913 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11914 {
11915   if(_mesh)
11916     _mesh->decrRef();
11917 }
11918
11919 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11920     _itc(itc),
11921     _bg(bg),_end(end)
11922 {
11923   if(_mesh)
11924     _mesh->incrRef();
11925 }
11926
11927 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11928 {
11929   if(_mesh)
11930     _mesh->decrRef();
11931 }
11932
11933 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11934 {
11935   return _type;
11936 }
11937
11938 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11939 {
11940   return _end-_bg;
11941 }
11942
11943 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11944 {
11945   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11946 }
11947
11948 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11949 {
11950   if(mesh)
11951     {
11952       mesh->incrRef();
11953       _nb_cell=mesh->getNumberOfCells();
11954     }
11955 }
11956
11957 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11958 {
11959   if(_mesh)
11960     _mesh->decrRef();
11961   delete _cell;
11962 }
11963
11964 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11965 {
11966   const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11967   const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11968   if(_cell_id<_nb_cell)
11969     {
11970       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11971       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11972       int startId=_cell_id;
11973       _cell_id+=nbOfElems;
11974       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11975     }
11976   else
11977     return 0;
11978 }
11979
11980 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11981 {
11982   if(mesh)
11983     {
11984       _conn=mesh->getNodalConnectivity()->getPointer();
11985       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11986     }
11987 }
11988
11989 void MEDCouplingUMeshCell::next()
11990 {
11991   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11992     {
11993       _conn+=_conn_lgth;
11994       _conn_indx++;
11995     }
11996   _conn_lgth=_conn_indx[1]-_conn_indx[0];
11997 }
11998
11999 std::string MEDCouplingUMeshCell::repr() const
12000 {
12001   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12002     {
12003       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
12004       oss << " : ";
12005       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
12006       return oss.str();
12007     }
12008   else
12009     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
12010 }
12011
12012 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
12013 {
12014   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12015     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
12016   else
12017     return INTERP_KERNEL::NORM_ERROR;
12018 }
12019
12020 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
12021 {
12022   lgth=_conn_lgth;
12023   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
12024     return _conn;
12025   else
12026     return 0;
12027 }