]> SALOME platform Git repositories - tools/medcoupling.git/blob - src/MEDCoupling/MEDCouplingUMesh.cxx
Salome HOME
Bug fix: findCellIdsOnBoundary() wrongly throwing if void mesh.
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2022  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 (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 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_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * 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
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * 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.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \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
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \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.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               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 !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           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)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \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
1344  *             precision.
1345  */
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1347 {
1348   checkFullyDefined();
1349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352   coords->recenterForMaxPrecision(eps);
1353   //
1354   mcIdType nbOfCells=getNumberOfCells();
1355   const mcIdType *conn=_nodal_connec->getConstPointer();
1356   const mcIdType *index=_nodal_connec_index->getConstPointer();
1357   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358   connINew->alloc(nbOfCells+1,1);
1359   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1363   bool changed=false;
1364   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1365     {
1366       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1367         {
1368           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1369           changed=true;
1370         }
1371       else
1372         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373       *connINewPtr=connNew->getNumberOfTuples();
1374     }
1375   if(changed)
1376     setConnectivity(connNew,connINew,false);
1377 }
1378
1379 /*!
1380  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382  * the format of the returned DataArrayIdType instance.
1383  *
1384  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1386  */
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1388 {
1389   checkConnectivityFullyDefined();
1390   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392   std::vector<bool> retS(maxElt,false);
1393   computeNodeIdsAlg(retS);
1394   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1395 }
1396
1397 /*!
1398  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1400  */
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1402 {
1403   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404            nbOfCells=getNumberOfCells();
1405   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406   for(mcIdType i=0;i<nbOfCells;i++)
1407     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1408       if(conn[j]>=0)
1409         {
1410           if(conn[j]<nbOfNodes)
1411             nodeIdsInUse[conn[j]]=true;
1412           else
1413             {
1414               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1415               throw INTERP_KERNEL::Exception(oss.str());
1416             }
1417         }
1418 }
1419
1420 /// @cond INTERNAL
1421
1422 struct MEDCouplingAccVisit
1423 {
1424   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426   mcIdType _new_nb_of_nodes;
1427 };
1428
1429 /// @endcond
1430
1431 /*!
1432  * Finds nodes not used in any cell and returns an array giving a new id to every node
1433  * by excluding the unused nodes, for which the array holds -1. The result array is
1434  * a mapping in "Old to New" mode.
1435  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438  *          if the node is unused or a new id else. The caller is to delete this
1439  *          array using decrRef() as it is no more needed.
1440  *  \throw If the coordinates array is not set.
1441  *  \throw If the nodal connectivity of cells is not defined.
1442  *  \throw If the nodal connectivity includes an invalid id.
1443  *
1444  *  \if ENABLE_EXAMPLES
1445  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1447  *  \endif
1448  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1449  */
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1451 {
1452   nbrOfNodesInUse=-1;
1453   mcIdType nbOfNodes(getNumberOfNodes());
1454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455   ret->alloc(nbOfNodes,1);
1456   mcIdType *traducer=ret->getPointer();
1457   std::fill(traducer,traducer+nbOfNodes,-1);
1458   mcIdType nbOfCells=getNumberOfCells();
1459   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460   const mcIdType *conn=_nodal_connec->getConstPointer();
1461   for(mcIdType i=0;i<nbOfCells;i++)
1462     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1463       if(conn[j]>=0)
1464         {
1465           if(conn[j]<nbOfNodes)
1466             traducer[conn[j]]=1;
1467           else
1468             {
1469               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1470               throw INTERP_KERNEL::Exception(oss.str());
1471             }
1472         }
1473   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1475   return ret.retn();
1476 }
1477
1478 /*!
1479  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480  * For each cell in \b this the number of nodes constituting cell is computed.
1481  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482  * So for pohyhedrons some nodes can be counted several times in the returned result.
1483  *
1484  * \return a newly allocated array
1485  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1486  */
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1488 {
1489   checkConnectivityFullyDefined();
1490   mcIdType nbOfCells=getNumberOfCells();
1491   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492   ret->alloc(nbOfCells,1);
1493   mcIdType *retPtr=ret->getPointer();
1494   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1497     {
1498       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499         *retPtr=connI[i+1]-connI[i]-1;
1500       else
1501         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1502     }
1503   return ret.retn();
1504 }
1505
1506 /*!
1507  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1509  *
1510  * \return DataArrayIdType * - new object to be deallocated by the caller.
1511  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1512  */
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1514 {
1515   checkConnectivityFullyDefined();
1516   mcIdType nbOfCells=getNumberOfCells();
1517   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518   ret->alloc(nbOfCells,1);
1519   mcIdType *retPtr=ret->getPointer();
1520   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1523     {
1524       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526         *retPtr=ToIdType(s.size());
1527       else
1528         {
1529           s.erase(-1);
1530           *retPtr=ToIdType(s.size());
1531         }
1532     }
1533   return ret.retn();
1534 }
1535
1536 /*!
1537  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1539  *
1540  * \return a newly allocated array
1541  */
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1543 {
1544   checkConnectivityFullyDefined();
1545   mcIdType nbOfCells=getNumberOfCells();
1546   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547   ret->alloc(nbOfCells,1);
1548   mcIdType *retPtr=ret->getPointer();
1549   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1552     {
1553       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1555     }
1556   return ret.retn();
1557 }
1558
1559 /*!
1560  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562  * array mean that the corresponding old node is no more used.
1563  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564  *           this->getNumberOfNodes() before call of this method. The caller is to
1565  *           delete this array using decrRef() as it is no more needed.
1566  *  \throw If the coordinates array is not set.
1567  *  \throw If the nodal connectivity of cells is not defined.
1568  *  \throw If the nodal connectivity includes an invalid id.
1569  *  \sa areAllNodesFetched
1570  *
1571  *  \if ENABLE_EXAMPLES
1572  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1574  *  \endif
1575  */
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1577 {
1578   return MEDCouplingPointSet::zipCoordsTraducer();
1579 }
1580
1581 /*!
1582  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1584  */
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1586 {
1587   switch(compType)
1588   {
1589     case 0:
1590       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1591     case 1:
1592       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1593     case 2:
1594       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1595     case 3:
1596       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1597     case 7:
1598       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1599   }
1600   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1610   return 0;
1611 }
1612
1613 /*!
1614  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1615  */
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1617 {
1618   mcIdType sz=connI[cell1+1]-connI[cell1];
1619   if(sz==connI[cell2+1]-connI[cell2])
1620     {
1621       if(conn[connI[cell1]]==conn[connI[cell2]])
1622         {
1623           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624           unsigned dim=cm.getDimension();
1625           if(dim!=3)
1626             {
1627               if(dim!=1)
1628                 {
1629                   mcIdType sz1=2*(sz-1);
1630                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634                   return work!=tmp+sz1?1:0;
1635                 }
1636               else
1637                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1638             }
1639           else
1640             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1641         }
1642     }
1643   return 0;
1644 }
1645
1646 /*!
1647  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1648  */
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1650 {
1651   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1652     {
1653       if(conn[connI[cell1]]==conn[connI[cell2]])
1654         {
1655           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1657           return s1==s2?1:0;
1658         }
1659     }
1660   return 0;
1661 }
1662
1663 /*!
1664  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1665  */
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1667 {
1668   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1669     {
1670       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1672       return s1==s2?1:0;
1673     }
1674   return 0;
1675 }
1676
1677 /*!
1678  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1679  */
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1681 {
1682   mcIdType sz=connI[cell1+1]-connI[cell1];
1683   if(sz==connI[cell2+1]-connI[cell2])
1684     {
1685       if(conn[connI[cell1]]==conn[connI[cell2]])
1686         {
1687           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688           unsigned dim=cm.getDimension();
1689           if(dim!=3)
1690             {
1691               if(dim!=1)
1692                 {
1693                   mcIdType sz1=2*(sz-1);
1694                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1698                   if(work!=tmp+sz1)
1699                     return 1;
1700                   else
1701                     {
1702                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1705                         return 2;
1706                       else
1707                         return 0;
1708                     }
1709                 }
1710               else
1711                 {//case of SEG2 and SEG3
1712                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1713                     return 1;
1714                   if(!cm.isQuadratic())
1715                     {
1716                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1719                         return 2;
1720                       return 0;
1721                     }
1722                   else
1723                     {
1724                       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])
1725                         return 2;
1726                       return 0;
1727                     }
1728                 }
1729             }
1730           else
1731             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 /*!
1739  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741  * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743  * This method is time consuming.
1744  *
1745  * \param [in] compType input specifying the technique used to compare cells each other.
1746  *   - 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.
1747  *   - 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)
1748  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749  *   - 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
1750  * can be used for users not sensitive to orientation of cell
1751  * \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.
1752  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1754  *
1755  */
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1757 {
1758   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759   getReverseNodalConnectivity(revNodal,revNodalI);
1760   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1761 }
1762
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1765 {
1766   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771   std::vector<bool> isFetched(nbOfCells,false);
1772   if(startCellId==0)
1773     {
1774       for(mcIdType i=startCellId;i<nbOfCells;i++)
1775         {
1776           if(!isFetched[i])
1777             {
1778               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779               std::vector<mcIdType> v,v2;
1780               if(connOfNode!=connPtr+connIPtr[i+1])
1781                 {
1782                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1784                   connOfNode++;
1785                 }
1786               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1787                 if(*connOfNode>=0)
1788                   {
1789                     v=v2;
1790                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792                     v2.resize(std::distance(v2.begin(),it));
1793                   }
1794               if(v2.size()>1)
1795                 {
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType pos=commonCellsI->back();
1799                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   else
1808     {
1809       for(mcIdType i=startCellId;i<nbOfCells;i++)
1810         {
1811           if(!isFetched[i])
1812             {
1813               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815               std::vector<mcIdType> v,v2;
1816               if(connOfNode!=connPtr+connIPtr[i+1])
1817                 {
1818                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1819                   connOfNode++;
1820                 }
1821               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1822                 if(*connOfNode>=0)
1823                   {
1824                     v=v2;
1825                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826                     v2.resize(std::distance(v2.begin(),it));
1827                   }
1828               // v2 contains now candidates. Problem candidates are sorted using id rank.
1829               if(v2.size()>1)
1830                 {
1831                   if(v2[0]!=i)
1832                   {
1833                     auto it(std::find(v2.begin(),v2.end(),i));
1834                     std::swap(*v2.begin(),*it);
1835                   }
1836                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1837                     {
1838                       mcIdType newPos(commonCells->getNumberOfTuples());
1839                       mcIdType pos(commonCellsI->back());
1840                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841                       commonCellsI->pushBackSilent(newPos);
1842                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843                         isFetched[*it]=true;
1844                     }
1845                 }
1846             }
1847         }
1848     }
1849   commonCellsArr=commonCells.retn();
1850   commonCellsIArr=commonCellsI.retn();
1851 }
1852
1853 /*!
1854  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856  * than \a this->getNumberOfCells() in the returned array means that there is no
1857  * corresponding cell in \a this mesh.
1858  * It is expected that \a this and \a other meshes share the same node coordinates
1859  * array, if it is not so an exception is thrown.
1860  *  \param [in] other - the mesh to compare with.
1861  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1862  *         valid values [0,1,2], see zipConnectivityTraducer().
1863  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1865  *         values. The caller is to delete this array using
1866  *         decrRef() as it is no more needed.
1867  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1868  *         mesh.
1869  *
1870  *  \if ENABLE_EXAMPLES
1871  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1873  *  \endif
1874  *  \sa checkDeepEquivalOnSameNodesWith()
1875  *  \sa checkGeoEquivalWith()
1876  */
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1878 {
1879   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880   mcIdType nbOfCells=getNumberOfCells();
1881   static const int possibleCompType[]={0,1,2};
1882   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1883     {
1884       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1886       oss << " !";
1887       throw INTERP_KERNEL::Exception(oss.str());
1888     }
1889   //
1890   if(other->getNumberOfCells()==0)
1891   {
1892     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1893     return true;
1894   }
1895   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898   mcIdType newNbOfCells=-1;
1899   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901   mcIdType maxPart(p0->getMaxValueInArray());
1902   bool ret(maxPart==newNbOfCells-1);
1903   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904   // fill p1 array in case of presence of cells in other not in this
1905   mcIdType *pt(p1->getPointer());
1906   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1907     pt[i+1] = i+1;
1908   //
1909   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1911   arr = p2.retn();
1912   return ret;
1913 }
1914
1915 /*!
1916  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917  * This method tries to determine if \b other is fully included in \b this.
1918  * The main difference is that this method is not expected to throw exception.
1919  * This method has two outputs :
1920  *
1921  * \param other other mesh
1922  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1924  */
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1926 {
1927   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928   DataArrayIdType *commonCells=0,*commonCellsI=0;
1929   mcIdType thisNbCells=getNumberOfCells();
1930   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933   mcIdType otherNbCells=other->getNumberOfCells();
1934   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935   arr2->alloc(otherNbCells,1);
1936   arr2->fillWithZero();
1937   mcIdType *arr2Ptr=arr2->getPointer();
1938   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939   for(mcIdType i=0;i<nbOfCommon;i++)
1940     {
1941       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942       if(start<thisNbCells)
1943         {
1944           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1945             {
1946               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947               mcIdType val=std::abs(commonCellsPtr[j])-1;
1948               if(val>=thisNbCells)
1949                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1950             }
1951         }
1952     }
1953   arr2->setName(other->getName());
1954   if(arr2->presenceOfValue(0))
1955     return false;
1956   arr=arr2.retn();
1957   return true;
1958 }
1959
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1961 {
1962   if(!other)
1963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1965   if(!otherC)
1966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967   std::vector<const MEDCouplingUMesh *> ms(2);
1968   ms[0]=this;
1969   ms[1]=otherC;
1970   return MergeUMeshesOnSameCoords(ms);
1971 }
1972
1973 /*!
1974  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976  * cellIds is not given explicitly but by a range python like.
1977  *
1978  * \param start starting ID
1979  * \param end end ID (excluded)
1980  * \param step step size
1981  * \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.
1982  * \return a newly allocated
1983  *
1984  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1986  */
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1988 {
1989   if(getMeshDimension()!=-1)
1990     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1991   else
1992     {
1993       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1994       if(newNbOfCells!=1)
1995         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1996       if(start!=0)
1997         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1998       incrRef();
1999       return const_cast<MEDCouplingUMesh *>(this);
2000     }
2001 }
2002
2003 /*!
2004  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005  * The result mesh shares or not the node coordinates array with \a this mesh depending
2006  * on \a keepCoords parameter.
2007  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008  *           to write this mesh to the MED file, its cells must be sorted using
2009  *           sortCellsInMEDFileFrmt().
2010  *  \param [in] begin - an array of cell ids to include to the new mesh.
2011  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2014  *         by calling zipCoords().
2015  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016  *         to delete this mesh using decrRef() as it is no more needed.
2017  *  \throw If the coordinates array is not set.
2018  *  \throw If the nodal connectivity of cells is not defined.
2019  *  \throw If any cell id in the array \a begin is not valid.
2020  *
2021  *  \if ENABLE_EXAMPLES
2022  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2024  *  \endif
2025  */
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2027 {
2028   if(getMeshDimension()!=-1)
2029     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2030   else
2031     {
2032       if(end-begin!=1)
2033         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2034       if(begin[0]!=0)
2035         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2036       incrRef();
2037       return const_cast<MEDCouplingUMesh *>(this);
2038     }
2039 }
2040
2041 /*!
2042  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2043  *
2044  * 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.
2045  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046  * The number of cells of \b this will remain the same with this method.
2047  *
2048  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050  * \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 ).
2051  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2052  */
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2054 {
2055   checkConnectivityFullyDefined();
2056   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2060     {
2061       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063       throw INTERP_KERNEL::Exception(oss.str());
2064     }
2065   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069       throw INTERP_KERNEL::Exception(oss.str());
2070     }
2071   mcIdType nbOfCells(getNumberOfCells());
2072   bool easyAssign(true);
2073   const mcIdType *connI(_nodal_connec_index->begin());
2074   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2076     {
2077       if(*it>=0 && *it<nbOfCells)
2078         {
2079           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2080         }
2081       else
2082         {
2083           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084           throw INTERP_KERNEL::Exception(oss.str());
2085         }
2086     }
2087   if(easyAssign)
2088     {
2089       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2090       computeTypes();
2091     }
2092   else
2093     {
2094       DataArrayIdType *arrOut=0,*arrIOut=0;
2095       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2096                                                arrOut,arrIOut);
2097       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098       setConnectivity(arrOut,arrIOut,true);
2099     }
2100 }
2101
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2103 {
2104   checkConnectivityFullyDefined();
2105   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2109     {
2110       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112       throw INTERP_KERNEL::Exception(oss.str());
2113     }
2114   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118       throw INTERP_KERNEL::Exception(oss.str());
2119     }
2120   mcIdType nbOfCells=getNumberOfCells();
2121   bool easyAssign=true;
2122   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2124   mcIdType it=start;
2125   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2126     {
2127       if(it>=0 && it<nbOfCells)
2128         {
2129           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2130         }
2131       else
2132         {
2133           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134           throw INTERP_KERNEL::Exception(oss.str());
2135         }
2136     }
2137   if(easyAssign)
2138     {
2139       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2140       computeTypes();
2141     }
2142   else
2143     {
2144       DataArrayIdType *arrOut=0,*arrIOut=0;
2145       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2146                                                 arrOut,arrIOut);
2147       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148       setConnectivity(arrOut,arrIOut,true);
2149     }
2150 }
2151
2152
2153 /*!
2154  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155  * this->getMeshDimension(), that bound some cells of \a this mesh.
2156  * The cells of lower dimension to include to the result mesh are selected basing on
2157  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160  * created mesh shares the node coordinates array with \a this mesh.
2161  *  \param [in] begin - the array of node ids.
2162  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164  *         array \a begin are added, else cells whose any node is in the
2165  *         array \a begin are added.
2166  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167  *         to delete this mesh using decrRef() as it is no more needed.
2168  *  \throw If the coordinates array is not set.
2169  *  \throw If the nodal connectivity of cells is not defined.
2170  *  \throw If any node id in \a begin is not valid.
2171  *
2172  *  \if ENABLE_EXAMPLES
2173  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2175  *  \endif
2176  */
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2178 {
2179   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2184 }
2185
2186 /*!
2187  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2191  *         by calling zipCoords().
2192  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193  *         to delete this mesh using decrRef() as it is no more needed.
2194  *  \throw If the coordinates array is not set.
2195  *  \throw If the nodal connectivity of cells is not defined.
2196  *
2197  *  \if ENABLE_EXAMPLES
2198  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2200  *  \endif
2201  */
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2203 {
2204   DataArrayIdType *desc=DataArrayIdType::New();
2205   DataArrayIdType *descIndx=DataArrayIdType::New();
2206   DataArrayIdType *revDesc=DataArrayIdType::New();
2207   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2208   //
2209   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2210   revDesc->decrRef();
2211   desc->decrRef();
2212   descIndx->decrRef();
2213   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215   std::vector<mcIdType> boundaryCells;
2216   for(mcIdType i=0;i<nbOfCells;i++)
2217     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218       boundaryCells.push_back(i);
2219   revDescIndx->decrRef();
2220   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2221   return ret;
2222 }
2223
2224 /*!
2225  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2228  */
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2230 {
2231   checkFullyDefined();
2232   MCAuto<DataArrayIdType> ret2(DataArrayIdType::New());
2233
2234   if (getNumberOfCells() == 0)
2235     {
2236       ret2->alloc(0,1);
2237       return ret2.retn();
2238     }
2239
2240   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
2241   //
2242   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2243   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2244   //
2245   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2246   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2247   const mcIdType *revDescPtr=revDesc->getConstPointer();
2248   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2249   mcIdType nbOfCells=getNumberOfCells();
2250   std::vector<bool> ret1(nbOfCells,false);
2251   mcIdType sz=0;
2252   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2253     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2254       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2255   //
2256   ret2->alloc(sz,1);
2257   mcIdType *ret2Ptr=ret2->getPointer();
2258   sz=0;
2259   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2260     if(*it)
2261       *ret2Ptr++=sz;
2262   ret2->setName("BoundaryCells");
2263   return ret2.retn();
2264 }
2265
2266 /*!
2267  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2268  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2269  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2270  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2271  *
2272  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2273  * 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
2274  * equals a cell in \b otherDimM1OnSameCoords.
2275  *
2276  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2277  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2278  *
2279  * \param [in] otherDimM1OnSameCoords other mesh
2280  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2281  * \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
2282  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2283  */
2284 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2285 {
2286   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2288   checkConnectivityFullyDefined();
2289   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2290   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2291     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2292   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2293   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2294   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2295   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2296   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2297   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2298   DataArrayIdType *idsOtherInConsti=0;
2299   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2300   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2301   if(!b)
2302     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2303   std::set<mcIdType> s1;
2304   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2305     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2306   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2307   s1arr_renum1->sort();
2308   cellIdsRk0=s0arr.retn();
2309   //cellIdsRk1=s_renum1.retn();
2310   cellIdsRk1=s1arr_renum1.retn();
2311 }
2312
2313 /*!
2314  * 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
2315  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2316  *
2317  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2318  */
2319 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2320 {
2321   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2322   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2323   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2324   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2325   //
2326   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2327   revDesc=0; desc=0; descIndx=0;
2328   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2329   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2330   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2331 }
2332
2333 /*!
2334  * Finds nodes lying on the boundary of \a this mesh.
2335  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2336  *          nodes. The caller is to delete this array using decrRef() as it is no
2337  *          more needed.
2338  *  \throw If the coordinates array is not set.
2339  *  \throw If the nodal connectivity of cells is node defined.
2340  *
2341  *  \if ENABLE_EXAMPLES
2342  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2343  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2344  *  \endif
2345  */
2346 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2347 {
2348   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2349   return skin->computeFetchedNodeIds();
2350 }
2351
2352 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2353 {
2354   incrRef();
2355   return const_cast<MEDCouplingUMesh *>(this);
2356 }
2357
2358 /*!
2359  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2360  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2361  * This method searches for nodes needed to be duplicated. Those are the nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2362  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords, it will be duplicated.
2363  * 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.
2364  *
2365  * \param [in] crackingMesh 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
2366  *             parameter is altered during the call.
2367  * \return node ids which need to be duplicated following the algorithm explained above.
2368  *
2369  */
2370 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& crackingMesh) const
2371 {
2372   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2373   // which mimicks the C++
2374   using DAInt = MCAuto<DataArrayIdType>;
2375   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2376
2377   checkFullyDefined();
2378   crackingMesh.checkFullyDefined();
2379   if(getCoords()!=crackingMesh.getCoords())
2380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2381   if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2382     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2383
2384   // Clean the M1 group (cracking mesh): the M1 cells which are part of M0 boundary are irrelevant (we can't create a crack on the boundary of M0!)
2385   MCUMesh m0skin = computeSkin();
2386   DataArrayIdType *idsToKeepP;
2387   m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2388   DAInt idsToKeep(idsToKeepP);
2389   DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells());  // discard cells on the skin of M0
2390   MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2391
2392   if (!otherDimM1OnSameCoords->getNumberOfCells())
2393     return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2394
2395   // Checking star-shaped M1 group:
2396   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2397   MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2398   DAInt dsi = rdit0->deltaShiftIndex();
2399   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);  // for 2D: if a point is connected to more than 2 segs. For 3D: if a seg is connected to more than two faces.
2400   if(idsTmp0->getNumberOfTuples())
2401     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2402   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2403
2404   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2405   // ie nodes belonging to the boundary "cells" (might be points) of M1
2406   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2407   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2408   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2409   // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2410   //    In 3D, some points on the boundary of M0 will NOT be duplicated (where as in 2D, points on the boundary of M0 are always duplicated)
2411   //    Think of a partial (plane) crack in a cube: the points at the tip of the crack and not located inside the volume of the cube are not duplicated
2412   //    although they are technically on the skin of the cube.
2413   DAInt fNodes = m0skin->computeFetchedNodeIds();
2414   DAInt notDup = 0;
2415   if (getMeshDimension() == 3)
2416     {
2417       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2418       MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2419       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2420       DataArrayIdType * corresp=0;
2421       meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2422       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2423       // In the cube example above, this is a U-shaped polyline.
2424       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2425       corresp->decrRef();
2426       if (validIds->getNumberOfTuples())
2427         {
2428           // Build the set of segments which are: in the desc mesh of the skin of the 3D mesh (M0) **and** in the desc mesh of the M1 group:
2429           // (the U-shaped polyline described above)
2430           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2431           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2432           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2433           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2434
2435           // Specific logic to handle singular points :
2436           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2437           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2438           //   algorithm would be duplicating too much ...
2439           // This is a costly algorithm so only go into it if a simple (non sufficient) criteria is met: a node connected to more than 3 segs in meshM2:
2440           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2441           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2442           dnu1=0;dnu2=0;dnu3=0;
2443           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2444           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2445           if (singPoints->getNumberOfTuples())
2446             {
2447               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2448               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2449               // should not be duplicated
2450               //    1. Extract N D cells touching U-shape line:
2451               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2452               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2453               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2454               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2455               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2456               DataArrayIdType *idsOfM1BNt;
2457               mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2458               DAInt idsOfM1BN(idsOfM1BNt);
2459               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2460               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2461               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2462               for(const auto& v: *idsOfM1BN)
2463                 {
2464                   if (v >= nCellsDesc)    // Keep valid match only
2465                     continue;
2466                   mcIdType idx0 = revDescIBNP[v];
2467                   // Keep the two cells on either side of the face v of M1:
2468                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2469                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2470                 }
2471               //    3. Build complement
2472               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2473               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2474               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2475               DAInt inters = boundNodes->buildIntersection(nod3);
2476               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2477             }
2478           notDup = xtrem->buildSubstraction(fNodes1);
2479         }
2480       else  // if (validIds-> ...)
2481         notDup = xtrem->buildSubstraction(fNodes);
2482     }
2483   else  // if (3D ...)
2484     notDup = xtrem->buildSubstraction(fNodes);
2485
2486   DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2487   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2488   return dupl.retn();
2489 }
2490
2491
2492 /*!
2493  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2494  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2495  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2496  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2497  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2498  *
2499  * \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.
2500  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2501  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2502  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2503  * \param [out] cellIdsNotModified cell ids in \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.
2504  *
2505  */
2506 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2507                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2508 {
2509   using DAInt = MCAuto<DataArrayIdType>;
2510   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2511
2512   checkFullyDefined();
2513   otherDimM1OnSameCoords.checkFullyDefined();
2514   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2515     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2516   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2517     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2518
2519   // Degenerated case - no nodes to duplicate
2520   if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2521     {
2522       cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2523       cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2524       return;
2525     }
2526
2527   // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2528   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2529   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2530   mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2531   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2532   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2533   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2534   DataArrayIdType *idsOfM1t;
2535   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2536   DAInt idsOfM1Large(idsOfM1t);
2537   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2538
2539   // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2540   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2541   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2542   DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2543   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2544   DataArrayIdType *neight=0, *neighIt=0;
2545   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2546   DAInt neighL(neight), neighIL(neighIt);
2547
2548   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2549   hitCellsLarge->fillWithValue(0);  // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2550   mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2551
2552   // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2553   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2554   for(const auto& v: *idsOfM1Large)
2555     {
2556       if (v >= nL) continue;   // Keep valid match only - see doc of areCellsIncludedIn()
2557       mcIdType idx0 = revDescILP[v];
2558       // Retrieve the two cells on either side of the face v of M1:
2559       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2560       std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2561       // Handle the spread zones on the two sides of the crack:
2562       for (const auto c: {c1, c2})
2563         {
2564           if (hitCellsLargeP[c]) continue;
2565           // Identify connex zone around this cell - if we find a value already assigned there, use it.
2566           mcIdType dnu;
2567           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2568           std::set<mcIdType> sv;
2569           for (const mcIdType& s: *spreadZone)
2570             if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2571           if (sv.size() > 1)
2572             // Strange: we find in the same spread zone a +1 and -1 !
2573             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2574           // If a valid value was found, use it:
2575           mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2576           // Hopefully this does not conflict with an potential value on the other side:
2577           mcIdType other = toOther[c];
2578           if (hitCellsLargeP[other])
2579             {
2580               if(val && hitCellsLargeP[other] != -val)
2581                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2582               // We do not yet have a value, but other side has one. Use it!
2583               if(!val) val = -hitCellsLargeP[other];
2584             }
2585           // Cover first initialisation:
2586           if (!val) val = 1;
2587           // And finally, fill the current spread zone:
2588           for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2589         }
2590     }
2591
2592   DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2593   DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2594
2595   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2596     {
2597       DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2598       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2599     }
2600   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2601   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2602   //
2603   cellIdsNeededToBeRenum=cellsRet1.retn();
2604   cellIdsNotModified=cellsRet2.retn();
2605 }
2606
2607 /*!
2608  * This method operates a modification of the connectivity and coords in \b this.
2609  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2610  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2611  * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2612  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2613  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2614  *
2615  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2616  *
2617  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2618  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2619  */
2620 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2621 {
2622   mcIdType nbOfNodes=getNumberOfNodes();
2623   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2624   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2625 }
2626
2627 /*!
2628  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2629  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2630  *
2631  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2632  *
2633  * \sa renumberNodesInConn
2634  */
2635 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2636 {
2637   checkConnectivityFullyDefined();
2638   mcIdType *conn(getNodalConnectivity()->getPointer());
2639   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2640   mcIdType nbOfCells=getNumberOfCells();
2641   for(mcIdType i=0;i<nbOfCells;i++)
2642     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2643       {
2644         mcIdType& node=conn[iconn];
2645         if(node>=0)//avoid polyhedron separator
2646           {
2647             node+=offset;
2648           }
2649       }
2650   _nodal_connec->declareAsNew();
2651   updateTime();
2652 }
2653
2654 /*!
2655  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2656  *  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
2657  *  of a big mesh.
2658  */
2659 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2660 {
2661   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2662 }
2663
2664 /*!
2665  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2666  *  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
2667  *  of a big mesh.
2668  */
2669 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2670 {
2671   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
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 mcIdType *newNodeNumbersO2N)
2690 {
2691   checkConnectivityFullyDefined();
2692   mcIdType *conn=getNodalConnectivity()->getPointer();
2693   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2694   mcIdType nbOfCells=getNumberOfCells();
2695   for(mcIdType i=0;i<nbOfCells;i++)
2696     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2697       {
2698         mcIdType& 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(mcIdType delta)
2716 {
2717   checkConnectivityFullyDefined();
2718   mcIdType *conn=getNodalConnectivity()->getPointer();
2719   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2720   mcIdType nbOfCells=getNumberOfCells();
2721   for(mcIdType i=0;i<nbOfCells;i++)
2722     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2723       {
2724         mcIdType& 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 explicitly the renumber array in nodes is not explicitly 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 mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2751 {
2752   checkConnectivityFullyDefined();
2753   std::map<mcIdType,mcIdType> m;
2754   mcIdType val=offset;
2755   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2756     m[*work]=val;
2757   mcIdType *conn=getNodalConnectivity()->getPointer();
2758   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2759   mcIdType nbOfCells=getNumberOfCells();
2760   for(mcIdType i=0;i<nbOfCells;i++)
2761     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2762       {
2763         mcIdType& node=conn[iconn];
2764         if(node>=0)//avoid polyhedron separator
2765           {
2766             std::map<mcIdType,mcIdType>::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 whether to check content of old2NewBg
2790  */
2791 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2792 {
2793   checkConnectivityFullyDefined();
2794   mcIdType nbCells=getNumberOfCells();
2795   const mcIdType *array=old2NewBg;
2796   if(check)
2797     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2798   //
2799   const mcIdType *conn=_nodal_connec->getConstPointer();
2800   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2801   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2802   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2803   const mcIdType *n2oPtr=n2o->begin();
2804   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2805   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2806   newConn->copyStringInfoFrom(*_nodal_connec);
2807   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2808   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2809   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2810   //
2811   mcIdType *newC=newConn->getPointer();
2812   mcIdType *newCI=newConnI->getPointer();
2813   mcIdType loc=0;
2814   newCI[0]=loc;
2815   for(mcIdType i=0;i<nbCells;i++)
2816     {
2817       mcIdType pos=n2oPtr[i];
2818       mcIdType 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<mcIdType *>(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 DataArrayIdType * - a new instance of DataArrayIdType 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 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2849 {
2850   MCAuto<DataArrayIdType> elems=DataArrayIdType::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 mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2859   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2860   const double* coords = getCoords()->getConstPointer();
2861   mcIdType nbOfCells=getNumberOfCells();
2862   for ( mcIdType 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 (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2871         {
2872           mcIdType 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 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2900 {
2901   MCAuto<DataArrayIdType> elems=DataArrayIdType::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 mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2910   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2911   const double* coords = getCoords()->getConstPointer();
2912   mcIdType nbOfCells=getNumberOfCells();
2913   for ( mcIdType 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 (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2922         {
2923           mcIdType 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(mcIdType cellId) const
2952 {
2953   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2954   if(cellId<_nodal_connec_index->getNbOfElems()-1)
2955     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2956   else
2957     {
2958       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2959       throw INTERP_KERNEL::Exception(oss.str());
2960     }
2961 }
2962
2963 /*!
2964  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2965  * This method does not throw exception if geometric type \a type is not in \a this.
2966  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2967  * The coordinates array is not considered here.
2968  *
2969  * \param [in] type the geometric type
2970  * \return cell ids in this having geometric type \a type.
2971  */
2972 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2973 {
2974
2975   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2976   ret->alloc(0,1);
2977   checkConnectivityFullyDefined();
2978   mcIdType nbCells=getNumberOfCells();
2979   int mdim=getMeshDimension();
2980   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2981   if(mdim!=ToIdType(cm.getDimension()))
2982     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2983   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2984   const mcIdType *pt=_nodal_connec->getConstPointer();
2985   for(mcIdType i=0;i<nbCells;i++)
2986     {
2987       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2988         ret->pushBackSilent(i);
2989     }
2990   return ret.retn();
2991 }
2992
2993 /*!
2994  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2995  */
2996 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2997 {
2998   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2999   mcIdType nbOfCells(getNumberOfCells()),ret(0);
3000   for(mcIdType i=0;i<nbOfCells;i++)
3001     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3002       ret++;
3003   return ret;
3004 }
3005
3006 /*!
3007  * Returns the nodal connectivity of a given cell.
3008  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3009  * all returned node ids can be used in getCoordinatesOfNode().
3010  *  \param [in] cellId - an id of the cell of interest.
3011  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3012  *         cleared before the appending.
3013  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3014  */
3015 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3016 {
3017   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3018   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3019     if(*w>=0)
3020       conn.push_back(*w);
3021 }
3022
3023 std::string MEDCouplingUMesh::simpleRepr() const
3024 {
3025   static const char msg0[]="No coordinates specified !";
3026   std::ostringstream ret;
3027   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3028   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3029   int tmpp1,tmpp2;
3030   double tt=getTime(tmpp1,tmpp2);
3031   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3032   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3033   if(_mesh_dim>=-1)
3034     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3035   else
3036     { ret << " Mesh dimension has not been set or is invalid !"; }
3037   if(_coords!=0)
3038     {
3039       const int spaceDim=getSpaceDimension();
3040       ret << spaceDim << "\nInfo attached on space dimension : ";
3041       for(int i=0;i<spaceDim;i++)
3042         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3043       ret << "\n";
3044     }
3045   else
3046     ret << msg0 << "\n";
3047   ret << "Number of nodes : ";
3048   if(_coords!=0)
3049     ret << getNumberOfNodes() << "\n";
3050   else
3051     ret << msg0 << "\n";
3052   ret << "Number of cells : ";
3053   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3054     ret << getNumberOfCells() << "\n";
3055   else
3056     ret << "No connectivity specified !" << "\n";
3057   ret << "Cell types present : ";
3058   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3059     {
3060       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3061       ret << cm.getRepr() << " ";
3062     }
3063   ret << "\n";
3064   return ret.str();
3065 }
3066
3067 std::string MEDCouplingUMesh::advancedRepr() const
3068 {
3069   std::ostringstream ret;
3070   ret << simpleRepr();
3071   ret << "\nCoordinates array : \n___________________\n\n";
3072   if(_coords)
3073     _coords->reprWithoutNameStream(ret);
3074   else
3075     ret << "No array set !\n";
3076   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3077   reprConnectivityOfThisLL(ret);
3078   return ret.str();
3079 }
3080
3081 /*!
3082  * This method returns a C++ code that is a dump of \a this.
3083  * This method will throw if this is not fully defined.
3084  */
3085 std::string MEDCouplingUMesh::cppRepr() const
3086 {
3087   static const char coordsName[]="coords";
3088   static const char connName[]="conn";
3089   static const char connIName[]="connI";
3090   checkFullyDefined();
3091   std::ostringstream ret; ret << "// coordinates" << std::endl;
3092   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3093   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3094   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3095   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3096   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3097   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3098   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3099   return ret.str();
3100 }
3101
3102 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3103 {
3104   std::ostringstream ret;
3105   reprConnectivityOfThisLL(ret);
3106   return ret.str();
3107 }
3108
3109 /*!
3110  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3111  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3112  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3113  * some algos).
3114  *
3115  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3116  * 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
3117  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3118  */
3119 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3120 {
3121   int mdim=getMeshDimension();
3122   if(mdim<0)
3123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3124   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3125   MCAuto<DataArrayIdType> tmp1,tmp2;
3126   bool needToCpyCT=true;
3127   if(!_nodal_connec)
3128     {
3129       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3130       needToCpyCT=false;
3131     }
3132   else
3133     {
3134       tmp1=_nodal_connec;
3135       tmp1->incrRef();
3136     }
3137   if(!_nodal_connec_index)
3138     {
3139       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3140       needToCpyCT=false;
3141     }
3142   else
3143     {
3144       tmp2=_nodal_connec_index;
3145       tmp2->incrRef();
3146     }
3147   ret->setConnectivity(tmp1,tmp2,false);
3148   if(needToCpyCT)
3149     ret->_types=_types;
3150   if(!_coords)
3151     {
3152       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3153       ret->setCoords(coords);
3154     }
3155   else
3156     ret->setCoords(_coords);
3157   return ret.retn();
3158 }
3159
3160 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3161 {
3162   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3163   const mcIdType *pt=_nodal_connec->getConstPointer();
3164   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3165     return ptI[cellId+1]-ptI[cellId]-1;
3166   else
3167     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3168 }
3169
3170 /*!
3171  * Returns types of cells of the specified part of \a this mesh.
3172  * This method avoids computing sub-mesh explicitly to get its types.
3173  *  \param [in] begin - an array of cell ids of interest.
3174  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3175  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3176  *         describing the cell types.
3177  *  \throw If the coordinates array is not set.
3178  *  \throw If the nodal connectivity of cells is not defined.
3179  *  \sa getAllGeoTypes()
3180  */
3181 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3182 {
3183   checkFullyDefined();
3184   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3185   const mcIdType *conn=_nodal_connec->getConstPointer();
3186   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3187   for(const mcIdType *w=begin;w!=end;w++)
3188     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3189   return ret;
3190 }
3191
3192 /*!
3193  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3194  * Optionally updates
3195  * a set of types of cells constituting \a this mesh.
3196  * This method is for advanced users having prepared their connectivity before. For
3197  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3198  *  \param [in] conn - the nodal connectivity array.
3199  *  \param [in] connIndex - the nodal connectivity index array.
3200  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3201  *         mesh is updated.
3202  */
3203 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3204 {
3205   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3206   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3207   if(isComputingTypes)
3208     computeTypes();
3209   declareAsNew();
3210 }
3211
3212 /*!
3213  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3214  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3215  */
3216 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3217     _nodal_connec(0),_nodal_connec_index(0),
3218     _types(other._types)
3219 {
3220   if(other._nodal_connec)
3221     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3222   if(other._nodal_connec_index)
3223     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3224 }
3225
3226 MEDCouplingUMesh::~MEDCouplingUMesh()
3227 {
3228   if(_nodal_connec)
3229     _nodal_connec->decrRef();
3230   if(_nodal_connec_index)
3231     _nodal_connec_index->decrRef();
3232 }
3233
3234 /*!
3235  * Recomputes a set of cell types of \a this mesh. For more info see
3236  * \ref MEDCouplingUMeshNodalConnectivity.
3237  */
3238 void MEDCouplingUMesh::computeTypes()
3239 {
3240   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3241 }
3242
3243
3244 /*!
3245  * Returns a number of cells constituting \a this mesh.
3246  *  \return mcIdType - the number of cells in \a this mesh.
3247  *  \throw If the nodal connectivity of cells is not defined.
3248  */
3249 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3250 {
3251   if(_nodal_connec_index)
3252     return _nodal_connec_index->getNumberOfTuples()-1;
3253   else
3254     if(_mesh_dim==-1)
3255       return 1;
3256     else
3257       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3258 }
3259
3260 /*!
3261  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3262  * mesh. For more info see \ref meshes.
3263  *  \return int - the dimension of \a this mesh.
3264  *  \throw If the mesh dimension is not defined using setMeshDimension().
3265  */
3266 int MEDCouplingUMesh::getMeshDimension() const
3267 {
3268   if(_mesh_dim<-1)
3269     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3270   return _mesh_dim;
3271 }
3272
3273 /*!
3274  * Returns a length of the nodal connectivity array.
3275  * This method is for test reason. Normally the integer returned is not useable by
3276  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3277  *  \return mcIdType - the length of the nodal connectivity array.
3278  */
3279 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3280 {
3281   return _nodal_connec->getNbOfElems();
3282 }
3283
3284 /*!
3285  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3286  */
3287 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3288 {
3289   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3290   tinyInfo.push_back(ToIdType(getMeshDimension()));
3291   tinyInfo.push_back(getNumberOfCells());
3292   if(_nodal_connec)
3293     tinyInfo.push_back(getNodalConnectivityArrayLen());
3294   else
3295     tinyInfo.push_back(-1);
3296 }
3297
3298 /*!
3299  * First step of unserialization process.
3300  */
3301 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3302 {
3303   return tinyInfo[6]<=0;
3304 }
3305
3306 /*!
3307  * Second step of serialization process.
3308  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3309  * \param a1 DataArrayDouble
3310  * \param a2 DataArrayDouble
3311  * \param littleStrings string vector
3312  */
3313 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3314 {
3315   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3316   if(tinyInfo[5]!=-1)
3317     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3318 }
3319
3320 /*!
3321  * Third and final step of serialization process.
3322  */
3323 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3324 {
3325   MEDCouplingPointSet::serialize(a1,a2);
3326   if(getMeshDimension()>-1)
3327     {
3328       a1=DataArrayIdType::New();
3329       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3330       mcIdType *ptA1=a1->getPointer();
3331       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3332       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3333       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3334       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3335     }
3336   else
3337     a1=0;
3338 }
3339
3340 /*!
3341  * Second and final unserialization process.
3342  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3343  */
3344 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3345 {
3346   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3347   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3348   if(tinyInfo[7]!=-1)
3349     {
3350       // Connectivity
3351       const mcIdType *recvBuffer=a1->getConstPointer();
3352       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3353       myConnecIndex->alloc(tinyInfo[6]+1,1);
3354       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3355       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3356       myConnec->alloc(tinyInfo[7],1);
3357       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3358       setConnectivity(myConnec, myConnecIndex);
3359     }
3360 }
3361
3362
3363
3364 /*!
3365  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3366  * mesh.<br>
3367  * For 1D cells, the returned field contains lengths.<br>
3368  * For 2D cells, the returned field contains areas.<br>
3369  * For 3D cells, the returned field contains volumes.
3370  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3371  *         orientation, i.e. the volume is always positive.
3372  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3373  *         and one time . The caller is to delete this field using decrRef() as it is no
3374  *         more needed.
3375  */
3376 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3377 {
3378   std::string name="MeasureOfMesh_";
3379   name+=getName();
3380   mcIdType nbelem=getNumberOfCells();
3381   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3382   field->setName(name);
3383   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3384   array->alloc(nbelem,1);
3385   double *area_vol=array->getPointer();
3386   field->setArray(array) ; array=0;
3387   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3388   field->synchronizeTimeWithMesh();
3389   if(getMeshDimension()!=-1)
3390     {
3391       mcIdType ipt;
3392       INTERP_KERNEL::NormalizedCellType type;
3393       int dim_space=getSpaceDimension();
3394       const double *coords=getCoords()->getConstPointer();
3395       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3396       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3397       for(mcIdType iel=0;iel<nbelem;iel++)
3398         {
3399           ipt=connec_index[iel];
3400           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3401           area_vol[iel]=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space);
3402         }
3403       if(isAbs)
3404         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3405     }
3406   else
3407     {
3408       area_vol[0]=std::numeric_limits<double>::max();
3409     }
3410   return field.retn();
3411 }
3412
3413 /*!
3414  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3415  * mesh.<br>
3416  * For 1D cells, the returned array contains lengths.<br>
3417  * For 2D cells, the returned array contains areas.<br>
3418  * For 3D cells, the returned array contains volumes.
3419  * This method avoids building explicitly a part of \a this mesh to perform the work.
3420  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3421  *         orientation, i.e. the volume is always positive.
3422  *  \param [in] begin - an array of cell ids of interest.
3423  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3424  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3425  *          delete this array using decrRef() as it is no more needed.
3426  *
3427  *  \if ENABLE_EXAMPLES
3428  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3429  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3430  *  \endif
3431  *  \sa getMeasureField()
3432  */
3433 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3434 {
3435   std::string name="PartMeasureOfMesh_";
3436   name+=getName();
3437   std::size_t nbelem=std::distance(begin,end);
3438   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3439   array->setName(name);
3440   array->alloc(nbelem,1);
3441   double *area_vol=array->getPointer();
3442   if(getMeshDimension()!=-1)
3443     {
3444       mcIdType ipt;
3445       INTERP_KERNEL::NormalizedCellType type;
3446       int dim_space=getSpaceDimension();
3447       const double *coords=getCoords()->getConstPointer();
3448       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3449       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3450       for(const mcIdType *iel=begin;iel!=end;iel++)
3451         {
3452           ipt=connec_index[*iel];
3453           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3454           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3455         }
3456       if(isAbs)
3457         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3458     }
3459   else
3460     {
3461       area_vol[0]=std::numeric_limits<double>::max();
3462     }
3463   return array.retn();
3464 }
3465
3466 /*!
3467  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3468  * \a this one. The returned field contains the dual cell volume for each corresponding
3469  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3470  *  the dual mesh in P1 sens of \a this.<br>
3471  * For 1D cells, the returned field contains lengths.<br>
3472  * For 2D cells, the returned field contains areas.<br>
3473  * For 3D cells, the returned field contains volumes.
3474  * This method is useful to check "P1*" conservative interpolators.
3475  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3476  *         orientation, i.e. the volume is always positive.
3477  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3478  *          nodes and one time. The caller is to delete this array using decrRef() as
3479  *          it is no more needed.
3480  */
3481 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3482 {
3483   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3484   std::string name="MeasureOnNodeOfMesh_";
3485   name+=getName();
3486   mcIdType nbNodes=getNumberOfNodes();
3487   MCAuto<DataArrayDouble> nnpc;
3488   {
3489     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3490     nnpc=tmp2->convertToDblArr();
3491   }
3492   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3493   const double *nnpcPtr(nnpc->begin());
3494   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3495   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3496   array->alloc(nbNodes,1);
3497   double *valsToFill=array->getPointer();
3498   std::fill(valsToFill,valsToFill+nbNodes,0.);
3499   const double *values=tmp->getArray()->getConstPointer();
3500   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3501   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3502   getReverseNodalConnectivity(da,daInd);
3503   const mcIdType *daPtr=da->getConstPointer();
3504   const mcIdType *daIPtr=daInd->getConstPointer();
3505   for(mcIdType i=0;i<nbNodes;i++)
3506     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3507       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3508   ret->setMesh(this);
3509   ret->setArray(array);
3510   return ret.retn();
3511 }
3512
3513 /*!
3514  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3515  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3516  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3517  * and are normalized.
3518  * <br> \a this can be either
3519  * - a  2D mesh in 2D or 3D space or
3520  * - an 1D mesh in 2D space.
3521  *
3522  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3523  *          cells and one time. The caller is to delete this field using decrRef() as
3524  *          it is no more needed.
3525  *  \throw If the nodal connectivity of cells is not defined.
3526  *  \throw If the coordinates array is not set.
3527  *  \throw If the mesh dimension is not set.
3528  *  \throw If the mesh and space dimension is not as specified above.
3529  */
3530 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3531 {
3532   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3533     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3534   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3535   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3536   mcIdType nbOfCells=getNumberOfCells();
3537   int nbComp=getMeshDimension()+1;
3538   array->alloc(nbOfCells,nbComp);
3539   double *vals=array->getPointer();
3540   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3541   const mcIdType *conn=_nodal_connec->getConstPointer();
3542   const double *coords=_coords->getConstPointer();
3543   if(getMeshDimension()==2)
3544     {
3545       if(getSpaceDimension()==3)
3546         {
3547           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3548           const double *locPtr=loc->getConstPointer();
3549           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3550             {
3551               mcIdType offset=connI[i];
3552               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3553               double n=INTERP_KERNEL::norm<3>(vals);
3554               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3555             }
3556         }
3557       else
3558         {
3559           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3560           const double *isAbsPtr=isAbs->getArray()->begin();
3561           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3562             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3563         }
3564     }
3565   else//meshdimension==1
3566     {
3567       double tmp[2];
3568       for(mcIdType i=0;i<nbOfCells;i++)
3569         {
3570           mcIdType offset=connI[i];
3571           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3572           double n=INTERP_KERNEL::norm<2>(tmp);
3573           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3574           *vals++=-tmp[1];
3575           *vals++=tmp[0];
3576         }
3577     }
3578   ret->setArray(array);
3579   ret->setMesh(this);
3580   ret->synchronizeTimeWithSupport();
3581   return ret.retn();
3582 }
3583
3584 /*!
3585  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3586  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3587  * and are normalized.
3588  * <br> \a this can be either
3589  * - a  2D mesh in 2D or 3D space or
3590  * - an 1D mesh in 2D space.
3591  *
3592  * This method avoids building explicitly a part of \a this mesh to perform the work.
3593  *  \param [in] begin - an array of cell ids of interest.
3594  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3595  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3596  *          cells and one time. The caller is to delete this field using decrRef() as
3597  *          it is no more needed.
3598  *  \throw If the nodal connectivity of cells is not defined.
3599  *  \throw If the coordinates array is not set.
3600  *  \throw If the mesh dimension is not set.
3601  *  \throw If the mesh and space dimension is not as specified above.
3602  *  \sa buildOrthogonalField()
3603  *
3604  *  \if ENABLE_EXAMPLES
3605  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3606  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3607  *  \endif
3608  */
3609 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3610 {
3611   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3612     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3613   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3614   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3615   std::size_t nbelems=std::distance(begin,end);
3616   int nbComp=getMeshDimension()+1;
3617   array->alloc(nbelems,nbComp);
3618   double *vals=array->getPointer();
3619   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3620   const mcIdType *conn=_nodal_connec->getConstPointer();
3621   const double *coords=_coords->getConstPointer();
3622   if(getMeshDimension()==2)
3623     {
3624       if(getSpaceDimension()==3)
3625         {
3626           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3627           const double *locPtr=loc->getConstPointer();
3628           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3629             {
3630               mcIdType offset=connI[*i];
3631               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3632               double n=INTERP_KERNEL::norm<3>(vals);
3633               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3634             }
3635         }
3636       else
3637         {
3638           for(std::size_t i=0;i<nbelems;i++)
3639             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3640         }
3641     }
3642   else//meshdimension==1
3643     {
3644       double tmp[2];
3645       for(const mcIdType *i=begin;i!=end;i++)
3646         {
3647           mcIdType offset=connI[*i];
3648           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3649           double n=INTERP_KERNEL::norm<2>(tmp);
3650           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3651           *vals++=-tmp[1];
3652           *vals++=tmp[0];
3653         }
3654     }
3655   ret->setArray(array);
3656   ret->setMesh(this);
3657   ret->synchronizeTimeWithSupport();
3658   return ret.retn();
3659 }
3660
3661 /*!
3662  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3663  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3664  * and are \b not normalized.
3665  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3666  *          cells and one time. The caller is to delete this field using decrRef() as
3667  *          it is no more needed.
3668  *  \throw If the nodal connectivity of cells is not defined.
3669  *  \throw If the coordinates array is not set.
3670  *  \throw If \a this->getMeshDimension() != 1.
3671  *  \throw If \a this mesh includes cells of type other than SEG2.
3672  */
3673 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3674 {
3675   if(getMeshDimension()!=1)
3676     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3677   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3678     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3679   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3680   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3681   mcIdType nbOfCells=getNumberOfCells();
3682   int spaceDim=getSpaceDimension();
3683   array->alloc(nbOfCells,spaceDim);
3684   double *pt=array->getPointer();
3685   const double *coo=getCoords()->getConstPointer();
3686   std::vector<mcIdType> conn;
3687   conn.reserve(2);
3688   for(mcIdType i=0;i<nbOfCells;i++)
3689     {
3690       conn.resize(0);
3691       getNodeIdsOfCell(i,conn);
3692       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3693     }
3694   ret->setArray(array);
3695   ret->setMesh(this);
3696   ret->synchronizeTimeWithSupport();
3697   return ret.retn();
3698 }
3699
3700 /*!
3701  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3702  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3703  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3704  * from. If a result face is shared by two 3D cells, then the face in included twice in
3705  * the result mesh.
3706  *  \param [in] origin - 3 components of a point defining location of the plane.
3707  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3708  *         must be greater than 1e-6.
3709  *  \param [in] eps - half-thickness of the plane.
3710  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3711  *         producing correspondent 2D cells. The caller is to delete this array
3712  *         using decrRef() as it is no more needed.
3713  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3714  *         not share the node coordinates array with \a this mesh. The caller is to
3715  *         delete this mesh using decrRef() as it is no more needed.
3716  *  \throw If the coordinates array is not set.
3717  *  \throw If the nodal connectivity of cells is not defined.
3718  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3719  *  \throw If magnitude of \a vec is less than 1e-6.
3720  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3721  *  \throw If \a this includes quadratic cells.
3722  */
3723 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3724 {
3725   checkFullyDefined();
3726   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3727     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3728   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3729   if(candidates->empty())
3730     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3731   std::vector<mcIdType> nodes;
3732   DataArrayIdType *cellIds1D=0;
3733   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3734   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3735   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3736   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3737   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3738   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3739   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3740   revDesc2=0; revDescIndx2=0;
3741   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3742   revDesc1=0; revDescIndx1=0;
3743   //Marking all 1D cells that contained at least one node located on the plane
3744   //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3745   //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3746   //due to accuracy errors when the needed nodes already exist)
3747   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3748   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3749   //
3750   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3751   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3752     cut3DCurve[*it]=-1;
3753   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3754   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3755   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3756                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3757                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3758   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3759   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3760   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3761   if(cellIds2->empty())
3762     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3763   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3764   ret->setCoords(mDesc1->getCoords());
3765   ret->setConnectivity(conn,connI,true);
3766   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3767   return ret.retn();
3768 }
3769
3770 /*!
3771  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3772 addition to the mesh, returns a new DataArrayIdType, 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
3773 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3774 the result mesh.
3775  *  \param [in] origin - 3 components of a point defining location of the plane.
3776  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3777  *         must be greater than 1e-6.
3778  *  \param [in] eps - half-thickness of the plane.
3779  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3780  *         producing correspondent segments. The caller is to delete this array
3781  *         using decrRef() as it is no more needed.
3782  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3783  *         mesh in 3D space. This mesh does not share the node coordinates array with
3784  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3785  *         no more needed.
3786  *  \throw If the coordinates array is not set.
3787  *  \throw If the nodal connectivity of cells is not defined.
3788  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3789  *  \throw If magnitude of \a vec is less than 1e-6.
3790  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3791  *  \throw If \a this includes quadratic cells.
3792  */
3793 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3794 {
3795   checkFullyDefined();
3796   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3797     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3798   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3799   if(candidates->empty())
3800     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3801   std::vector<mcIdType> nodes;
3802   DataArrayIdType *cellIds1D(0);
3803   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3804   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3805   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3806   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3807   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3808   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3809   //
3810   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3811   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3812     cut3DCurve[*it]=-1;
3813   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3814   mcIdType ncellsSub=subMesh->getNumberOfCells();
3815   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3816   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3817                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3818                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3819   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3820   conn->alloc(0,1);
3821   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3822   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3823   for(mcIdType i=0;i<ncellsSub;i++)
3824     {
3825       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3826         {
3827           if(cut3DSurf[i].first!=-2)
3828             {
3829               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3830               connI->pushBackSilent(conn->getNumberOfTuples());
3831               cellIds2->pushBackSilent(i);
3832             }
3833           else
3834             {
3835               mcIdType cellId3DSurf=cut3DSurf[i].second;
3836               mcIdType offset=nodalI[cellId3DSurf]+1;
3837               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3838               for(mcIdType j=0;j<nbOfEdges;j++)
3839                 {
3840                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3841                   connI->pushBackSilent(conn->getNumberOfTuples());
3842                   cellIds2->pushBackSilent(cellId3DSurf);
3843                 }
3844             }
3845         }
3846     }
3847   if(cellIds2->empty())
3848     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3849   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3850   ret->setCoords(mDesc1->getCoords());
3851   ret->setConnectivity(conn,connI,true);
3852   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3853   return ret.retn();
3854 }
3855
3856 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3857 {
3858   checkFullyDefined();
3859   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3860     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3861   if(getNumberOfCells()!=1)
3862     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3863   //
3864   std::vector<mcIdType> nodes;
3865   findNodesOnPlane(origin,vec,eps,nodes);
3866   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),desc2(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),descIndx2(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDesc2(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New()),revDescIndx2(DataArrayIdType::New());
3867   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3868   revDesc2=0; revDescIndx2=0;
3869   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3870   revDesc1=0; revDescIndx1=0;
3871   DataArrayIdType *cellIds1D(0);
3872   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3873   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3874   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3875   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3876     cut3DCurve[*it]=-1;
3877   bool sameNbNodes;
3878   {
3879     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3880     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3881     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3882   }
3883   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3884   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3885                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3886                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3887   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3888   connI->pushBackSilent(0); conn->alloc(0,1);
3889   {
3890     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3891     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3892     if(cellIds2->empty())
3893       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3894   }
3895   std::vector<std::vector<mcIdType> > res;
3896   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3897   std::size_t sz(res.size());
3898   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3899     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3900   for(std::size_t i=0;i<sz;i++)
3901     {
3902       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3903       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3904       connI->pushBackSilent(conn->getNumberOfTuples());
3905     }
3906   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3907   ret->setCoords(mDesc1->getCoords());
3908   ret->setConnectivity(conn,connI,true);
3909   mcIdType nbCellsRet(ret->getNumberOfCells());
3910   //
3911   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3912   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3913   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3914   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3915   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3916   MCAuto<DataArrayDouble> occm;
3917   {
3918     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3919     occm=DataArrayDouble::Substract(ccm,pt);
3920   }
3921   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3922   vec2->setPartOfValuesSimple1(vec[0],0,nbCellsRet,1,0,1,1); vec2->setPartOfValuesSimple1(vec[1],0,nbCellsRet,1,1,2,1); vec2->setPartOfValuesSimple1(vec[2],0,nbCellsRet,1,2,3,1);
3923   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3924   //
3925   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3926   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3927   ret2->setCoords(mDesc1->getCoords());
3928   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3929   conn2I->pushBackSilent(0); conn2->alloc(0,1);
3930   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3931   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3932   if(dott->getIJ(0,0)>0)
3933     {
3934       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3935       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3936     }
3937   else
3938     {
3939       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3940       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3941     }
3942   for(mcIdType i=1;i<nbCellsRet;i++)
3943     {
3944       if(dott2->getIJ(i,0)<0)
3945         {
3946           if(ciPtr[i+1]-ciPtr[i]>=4)
3947             {
3948               cell0.push_back(-1);
3949               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3950             }
3951         }
3952       else
3953         {
3954           if(ciPtr[i+1]-ciPtr[i]>=4)
3955             {
3956               cell1.push_back(-1);
3957               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3958             }
3959         }
3960     }
3961   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3962   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3963   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3964   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3965   ret2->setConnectivity(conn2,conn2I,true);
3966   ret2->checkConsistencyLight();
3967   ret2->orientCorrectlyPolyhedrons();
3968   return ret2;
3969 }
3970
3971 /*!
3972  * Finds cells whose bounding boxes intersect a given plane.
3973  *  \param [in] origin - 3 components of a point defining location of the plane.
3974  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3975  *         must be greater than 1e-6.
3976  *  \param [in] eps - half-thickness of the plane.
3977  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3978  *         cells. The caller is to delete this array using decrRef() as it is no more
3979  *         needed.
3980  *  \throw If the coordinates array is not set.
3981  *  \throw If the nodal connectivity of cells is not defined.
3982  *  \throw If \a this->getSpaceDimension() != 3.
3983  *  \throw If magnitude of \a vec is less than 1e-6.
3984  *  \sa buildSlice3D()
3985  */
3986 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3987 {
3988   checkFullyDefined();
3989   if(getSpaceDimension()!=3)
3990     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3991   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3992   if(normm<1e-6)
3993     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3994   double vec2[3];
3995   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3996   double angle=acos(vec[2]/normm);
3997   MCAuto<DataArrayIdType> cellIds;
3998   double bbox[6];
3999   if(angle>eps)
4000     {
4001       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4002       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4003       if(normm2/normm>1e-6)
4004         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4005       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4006       mw->setCoords(coo);
4007       mw->getBoundingBox(bbox);
4008       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4009       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4010     }
4011   else
4012     {
4013       getBoundingBox(bbox);
4014       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4015       cellIds=getCellsInBoundingBox(bbox,eps);
4016     }
4017   return cellIds.retn();
4018 }
4019
4020 /*!
4021  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4022  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4023  * No consideration of coordinate is done by this method.
4024  * 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)
4025  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4026  */
4027 bool MEDCouplingUMesh::isContiguous1D() const
4028 {
4029   if(getMeshDimension()!=1)
4030     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4031   mcIdType nbCells=getNumberOfCells();
4032   if(nbCells<1)
4033     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4034   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4035   mcIdType ref=conn[connI[0]+2];
4036   for(mcIdType i=1;i<nbCells;i++)
4037     {
4038       if(conn[connI[i]+1]!=ref)
4039         return false;
4040       ref=conn[connI[i]+2];
4041     }
4042   return true;
4043 }
4044
4045 /*!
4046  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4047  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4048  * \param pt reference point of the line
4049  * \param v normalized director vector of the line
4050  * \param eps max precision before throwing an exception
4051  * \param res output of size this->getNumberOfCells
4052  */
4053 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4054 {
4055   if(getMeshDimension()!=1)
4056     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4057   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4058     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4059   if(getSpaceDimension()!=3)
4060     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4061   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4062   const double *fPtr=f->getArray()->getConstPointer();
4063   double tmp[3];
4064   for(mcIdType i=0;i<getNumberOfCells();i++)
4065     {
4066       const double *tmp1=fPtr+3*i;
4067       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4068       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4069       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4070       double n1=INTERP_KERNEL::norm<3>(tmp);
4071       n1/=INTERP_KERNEL::norm<3>(tmp1);
4072       if(n1>eps)
4073         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4074     }
4075   const double *coo=getCoords()->getConstPointer();
4076   for(mcIdType i=0;i<getNumberOfNodes();i++)
4077     {
4078       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4079       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4080       res[i]=std::accumulate(tmp,tmp+3,0.);
4081     }
4082 }
4083
4084 /*!
4085  * 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.
4086  * \a this is expected to be a mesh so that its space dimension is equal to its
4087  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4088  * 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).
4089  *
4090  * 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
4091  * 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).
4092  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4093  *
4094  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4095  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4096  *
4097  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4098  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4099  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4100  * \return the positive value of the distance.
4101  * \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
4102  * dimension - 1.
4103  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4104  */
4105 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4106 {
4107   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4108   if(meshDim!=spaceDim-1)
4109     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4110   if(meshDim!=2 && meshDim!=1)
4111     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4112   checkFullyDefined();
4113   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4114     { 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()); }
4115   DataArrayIdType *ret1=0;
4116   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4117   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4118   MCAuto<DataArrayIdType> ret1Safe(ret1);
4119   cellId=*ret1Safe->begin();
4120   return *ret0->begin();
4121 }
4122
4123 /*!
4124  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4125  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4126  * 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
4127  * 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).
4128  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4129  *
4130  * \a this is expected to be a mesh so that its space dimension is equal to its
4131  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4132  * 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).
4133  *
4134  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4135  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4136  *
4137  * \param [in] pts the list of points in which each tuple represents a point
4138  * \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.
4139  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4140  * \throw if number of components of \a pts is not equal to the space dimension.
4141  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4142  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4143  */
4144 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4145 {
4146   if(!pts)
4147     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4148   pts->checkAllocated();
4149   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4150   if(meshDim!=spaceDim-1)
4151     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4152   if(meshDim!=2 && meshDim!=1)
4153     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4154   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4155     {
4156       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4157       throw INTERP_KERNEL::Exception(oss.str());
4158     }
4159   checkFullyDefined();
4160   mcIdType nbCells=getNumberOfCells();
4161   if(nbCells==0)
4162     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4163   mcIdType nbOfPts=pts->getNumberOfTuples();
4164   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4165   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4166   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4167   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4168   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4169   const double *bbox(bboxArr->begin());
4170   switch(spaceDim)
4171   {
4172     case 3:
4173       {
4174         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4175         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4176           {
4177             double x=std::numeric_limits<double>::max();
4178             std::vector<mcIdType> elems;
4179             myTree.getMinDistanceOfMax(ptsPtr,x);
4180             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4181             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4182           }
4183         break;
4184       }
4185     case 2:
4186       {
4187         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4188         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4189           {
4190             double x=std::numeric_limits<double>::max();
4191             std::vector<mcIdType> elems;
4192             myTree.getMinDistanceOfMax(ptsPtr,x);
4193             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4194             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4195           }
4196         break;
4197       }
4198     default:
4199       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4200   }
4201   cellIds=ret1.retn();
4202   return ret0.retn();
4203 }
4204
4205 /// @cond INTERNAL
4206
4207 /// @endcond
4208
4209 /*!
4210  * Finds cells in contact with a ball (i.e. a point with precision).
4211  * 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.
4212  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4213  *
4214  * \warning This method is suitable if the caller intends to evaluate only one
4215  *          point, for more points getCellsContainingPoints() is recommended as it is
4216  *          faster.
4217  *  \param [in] pos - array of coordinates of the ball central point.
4218  *  \param [in] eps - ball radius.
4219  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4220  *         if there are no such cells.
4221  *  \throw If the coordinates array is not set.
4222  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4223  */
4224 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4225 {
4226   std::vector<mcIdType> elts;
4227   getCellsContainingPoint(pos,eps,elts);
4228   if(elts.empty())
4229     return -1;
4230   return elts.front();
4231 }
4232
4233 /*!
4234  * Finds cells in contact with a ball (i.e. a point with precision).
4235  * 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.
4236  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4237  * \warning This method is suitable if the caller intends to evaluate only one
4238  *          point, for more points getCellsContainingPoints() is recommended as it is
4239  *          faster.
4240  *  \param [in] pos - array of coordinates of the ball central point.
4241  *  \param [in] eps - ball radius.
4242  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4243  *         before inserting ids.
4244  *  \throw If the coordinates array is not set.
4245  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4246  *
4247  *  \if ENABLE_EXAMPLES
4248  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4249  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4250  *  \endif
4251  */
4252 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4253 {
4254   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4255   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4256   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4257 }
4258
4259 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4260                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4261                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4262 {
4263   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4264   if(spaceDim==3)
4265     {
4266       if(mDim==3)
4267         {
4268           const double *coords=_coords->getConstPointer();
4269           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4270         }
4271       else
4272         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4273     }
4274   else if(spaceDim==2)
4275     {
4276       if(mDim==2)
4277         {
4278           const double *coords=_coords->getConstPointer();
4279           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4280         }
4281       else
4282         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4283     }
4284   else if(spaceDim==1)
4285     {
4286       if(mDim==1)
4287         {
4288           const double *coords=_coords->getConstPointer();
4289           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4290         }
4291       else
4292         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4293     }
4294   else
4295     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4296 }
4297
4298 /*!
4299  * Finds cells in contact with several balls (i.e. points with precision).
4300  * This method is an extension of getCellContainingPoint() and
4301  * getCellsContainingPoint() for the case of multiple points.
4302  * 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.
4303  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4304  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4305  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4306  *         this->getSpaceDimension() * \a nbOfPoints
4307  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4308  *  \param [in] eps - radius of balls (i.e. the precision).
4309  *  \param [out] elts - vector returning ids of found cells.
4310  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4311  *         dividing cell ids in \a elts into groups each referring to one
4312  *         point. Its every element (except the last one) is an index pointing to the
4313  *         first id of a group of cells. For example cells in contact with the *i*-th
4314  *         point are described by following range of indices:
4315  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4316  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4317  *         Number of cells in contact with the *i*-th point is
4318  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4319  *  \throw If the coordinates array is not set.
4320  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4321  *
4322  *  \if ENABLE_EXAMPLES
4323  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4324  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4325  *  \endif
4326  */
4327 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4328                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4329 {
4330   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4331   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4332 }
4333
4334 /*!
4335  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4336  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4337  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4338  * 
4339  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4340  */
4341 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4342 {
4343   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4344   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4345 }
4346
4347 /*!
4348  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4349  * least two its edges intersect each other anywhere except their extremities. An
4350  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4351  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4352  *         cleared before filling in.
4353  *  \param [in] eps - precision.
4354  *  \throw If \a this->getMeshDimension() != 2.
4355  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4356  */
4357 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4358 {
4359   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4360   if(getMeshDimension()!=2)
4361     throw INTERP_KERNEL::Exception(msg);
4362   int spaceDim=getSpaceDimension();
4363   if(spaceDim!=2 && spaceDim!=3)
4364     throw INTERP_KERNEL::Exception(msg);
4365   const mcIdType *conn=_nodal_connec->getConstPointer();
4366   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4367   mcIdType nbOfCells=getNumberOfCells();
4368   std::vector<double> cell2DinS2;
4369   for(mcIdType i=0;i<nbOfCells;i++)
4370     {
4371       mcIdType offset=connI[i];
4372       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4373       if(nbOfNodesForCell<=3)
4374         continue;
4375       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4376       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4377       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4378         cells.push_back(i);
4379       cell2DinS2.clear();
4380     }
4381 }
4382
4383 /*!
4384  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4385  *
4386  * 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.
4387  * 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.
4388  *
4389  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4390  * This convex envelop is computed using Jarvis march algorithm.
4391  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4392  * 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)
4393  * 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.
4394  *
4395  * \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.
4396  * \sa MEDCouplingUMesh::colinearize2D
4397  */
4398 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4399 {
4400   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4401     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4402   checkFullyDefined();
4403   const double *coords=getCoords()->getConstPointer();
4404   mcIdType nbOfCells=getNumberOfCells();
4405   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4406   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4407   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4408   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4409   *workIndexOut=0;
4410   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4411   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4412   std::set<INTERP_KERNEL::NormalizedCellType> types;
4413   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4414   isChanged->alloc(0,1);
4415   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4416     {
4417       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4418       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4419         isChanged->pushBackSilent(i);
4420       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4421       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4422     }
4423   if(isChanged->empty())
4424     return 0;
4425   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4426   _types=types;
4427   return isChanged.retn();
4428 }
4429
4430 /*!
4431  * This method is \b NOT const because it can modify \a this.
4432  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4433  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4434  * \param policy specifies the type of extrusion chosen:
4435  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4436  *   will be repeated to build each level
4437  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4438  *   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
4439  *   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
4440  *   arc.
4441  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4442  */
4443 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4444 {
4445   checkFullyDefined();
4446   mesh1D->checkFullyDefined();
4447   if(!mesh1D->isContiguous1D())
4448     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4449   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4450     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4451   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4452     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4453   if(mesh1D->getMeshDimension()!=1)
4454     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4455   bool isQuad=false;
4456   if(isPresenceOfQuadratic())
4457     {
4458       if(mesh1D->isFullyQuadratic())
4459         isQuad=true;
4460       else
4461         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4462     }
4463   mcIdType oldNbOfNodes(getNumberOfNodes());
4464   MCAuto<DataArrayDouble> newCoords;
4465   switch(policy)
4466   {
4467     case 0:
4468       {
4469         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4470         break;
4471       }
4472     case 1:
4473       {
4474         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4475         break;
4476       }
4477     default:
4478       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4479   }
4480   setCoords(newCoords);
4481   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4482   updateTime();
4483   return ret.retn();
4484 }
4485
4486
4487 /*!
4488  * Checks if \a this mesh is constituted by only quadratic cells.
4489  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4490  *  \throw If the coordinates array is not set.
4491  *  \throw If the nodal connectivity of cells is not defined.
4492  */
4493 bool MEDCouplingUMesh::isFullyQuadratic() const
4494 {
4495   checkFullyDefined();
4496   bool ret=true;
4497   mcIdType nbOfCells=getNumberOfCells();
4498   for(mcIdType i=0;i<nbOfCells && ret;i++)
4499     {
4500       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4501       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4502       ret=cm.isQuadratic();
4503     }
4504   return ret;
4505 }
4506
4507 /*!
4508  * Checks if \a this mesh includes any quadratic cell.
4509  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4510  *  \throw If the coordinates array is not set.
4511  *  \throw If the nodal connectivity of cells is not defined.
4512  */
4513 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4514 {
4515   checkFullyDefined();
4516   bool ret=false;
4517   mcIdType nbOfCells=getNumberOfCells();
4518   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4519     {
4520       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4521       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4522       ret=cm.isQuadratic();
4523     }
4524   return ret;
4525 }
4526
4527 /*!
4528  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4529  * this mesh, it remains unchanged.
4530  *  \throw If the coordinates array is not set.
4531  *  \throw If the nodal connectivity of cells is not defined.
4532  */
4533 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4534 {
4535   checkFullyDefined();
4536   mcIdType nbOfCells=getNumberOfCells();
4537   mcIdType delta=0;
4538   const mcIdType *iciptr=_nodal_connec_index->begin();
4539   for(mcIdType i=0;i<nbOfCells;i++)
4540     {
4541       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4542       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4543       if(cm.isQuadratic())
4544         {
4545           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4546           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4547           if(!cml.isDynamic())
4548             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4549           else
4550             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4551         }
4552     }
4553   if(delta==0)
4554     return ;
4555   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4556   const mcIdType *icptr(_nodal_connec->begin());
4557   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4558   newConnI->alloc(nbOfCells+1,1);
4559   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4560   *ociptr=0;
4561   _types.clear();
4562   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4563     {
4564       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4565       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4566       if(!cm.isQuadratic())
4567         {
4568           _types.insert(type);
4569           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4570           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4571         }
4572       else
4573         {
4574           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4575           _types.insert(typel);
4576           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4577           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4578           if(cml.isDynamic())
4579             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4580           *ocptr++=ToIdType(typel);
4581           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4582           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4583         }
4584     }
4585   setConnectivity(newConn,newConnI,false);
4586 }
4587
4588 /*!
4589  * This method converts all linear cell in \a this to quadratic one.
4590  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4591  * 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)
4592  * 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.
4593  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4594  * end of the existing coordinates.
4595  *
4596  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4597  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4598  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4599  *
4600  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4601  *
4602  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4603  */
4604 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4605 {
4606   DataArrayIdType *conn=0,*connI=0;
4607   DataArrayDouble *coords=0;
4608   std::set<INTERP_KERNEL::NormalizedCellType> types;
4609   checkFullyDefined();
4610   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4611   MCAuto<DataArrayDouble> coordsSafe;
4612   int meshDim=getMeshDimension();
4613   switch(conversionType)
4614   {
4615     case 0:
4616       switch(meshDim)
4617       {
4618         case 1:
4619           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4620           connSafe=conn; connISafe=connI; coordsSafe=coords;
4621           break;
4622         case 2:
4623           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4624           connSafe=conn; connISafe=connI; coordsSafe=coords;
4625           break;
4626         case 3:
4627           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4628           connSafe=conn; connISafe=connI; coordsSafe=coords;
4629           break;
4630         default:
4631           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4632       }
4633       break;
4634         case 1:
4635           {
4636             switch(meshDim)
4637             {
4638               case 1:
4639                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4640                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4641                 break;
4642               case 2:
4643                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4644                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4645                 break;
4646               case 3:
4647                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4648                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4649                 break;
4650               default:
4651                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4652             }
4653             break;
4654           }
4655         default:
4656           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4657   }
4658   setConnectivity(connSafe,connISafe,false);
4659   _types=types;
4660   setCoords(coordsSafe);
4661   return ret.retn();
4662 }
4663
4664 /*!
4665  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4666  * so that the number of cells remains the same. Quadratic faces are converted to
4667  * polygons. This method works only for 2D meshes in
4668  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4669  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4670  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4671  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4672  *         a polylinized edge constituting the input polygon.
4673  *  \throw If the coordinates array is not set.
4674  *  \throw If the nodal connectivity of cells is not defined.
4675  *  \throw If \a this->getMeshDimension() != 2.
4676  *  \throw If \a this->getSpaceDimension() != 2.
4677  */
4678 void MEDCouplingUMesh::tessellate2D(double eps)
4679 {
4680   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4681   if(spaceDim!=2)
4682     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4683   switch(meshDim)
4684     {
4685     case 1:
4686       return tessellate2DCurveInternal(eps);
4687     case 2:
4688       return tessellate2DInternal(eps);
4689     default:
4690       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4691     }
4692 }
4693
4694 #if 0
4695 /*!
4696  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4697  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4698  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4699  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4700  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4701  * This method can be seen as the opposite method of colinearize2D.
4702  * 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
4703  * to avoid to modify the numbering of existing nodes.
4704  *
4705  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4706  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4707  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4708  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4709  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4710  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4711  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4712  *
4713  * \sa buildDescendingConnectivity2
4714  */
4715 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4716                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4717 {
4718   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4719     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4720   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4721   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4722     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4723   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4724     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4725   //DataArrayIdType *out0(0),*outi0(0);
4726   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4727   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4728   //out0s=out0s->buildUnique(); out0s->sort(true);
4729 }
4730 #endif
4731
4732
4733 /*!
4734  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4735  * In addition, returns an array mapping new cells to old ones. <br>
4736  * This method typically increases the number of cells in \a this mesh
4737  * but the number of nodes remains \b unchanged.
4738  * That's why the 3D splitting policies
4739  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4740  *  \param [in] policy - specifies a pattern used for splitting.
4741  * The semantic of \a policy is:
4742  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4743  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4744  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4745  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4746  *
4747  *
4748  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4749  *          an id of old cell producing it. The caller is to delete this array using
4750  *         decrRef() as it is no more needed.
4751  *
4752  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4753  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4754  *          and \a this->getMeshDimension() != 3.
4755  *  \throw If \a policy is not one of the four discussed above.
4756  *  \throw If the nodal connectivity of cells is not defined.
4757  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4758  */
4759 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4760 {
4761   switch(policy)
4762   {
4763     case 0:
4764       return simplexizePol0();
4765     case 1:
4766       return simplexizePol1();
4767     case INTERP_KERNEL::PLANAR_FACE_5:
4768         return simplexizePlanarFace5();
4769     case INTERP_KERNEL::PLANAR_FACE_6:
4770         return simplexizePlanarFace6();
4771     default:
4772       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)");
4773   }
4774 }
4775
4776 /*!
4777  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4778  * - 1D: INTERP_KERNEL::NORM_SEG2
4779  * - 2D: INTERP_KERNEL::NORM_TRI3
4780  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4781  *
4782  * This method is useful for users that need to use P1 field services as
4783  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4784  * All these methods need mesh support containing only simplex cells.
4785  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4786  *  \throw If the coordinates array is not set.
4787  *  \throw If the nodal connectivity of cells is not defined.
4788  *  \throw If \a this->getMeshDimension() < 1.
4789  */
4790 bool MEDCouplingUMesh::areOnlySimplexCells() const
4791 {
4792   checkFullyDefined();
4793   int mdim=getMeshDimension();
4794   if(mdim<1 || mdim>3)
4795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4796   mcIdType nbCells=getNumberOfCells();
4797   const mcIdType *conn=_nodal_connec->begin();
4798   const mcIdType *connI=_nodal_connec_index->begin();
4799   for(mcIdType i=0;i<nbCells;i++)
4800     {
4801       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4802       if(!cm.isSimplex())
4803         return false;
4804     }
4805   return true;
4806 }
4807
4808
4809
4810 /*!
4811  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4812  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4813  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4814  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4815  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4816  * so it can be useful to call mergeNodes() before calling this method.
4817  *  \throw If \a this->getMeshDimension() <= 1.
4818  *  \throw If the coordinates array is not set.
4819  *  \throw If the nodal connectivity of cells is not defined.
4820  */
4821 void MEDCouplingUMesh::convertDegeneratedCells()
4822 {
4823   checkFullyDefined();
4824   if(getMeshDimension()<=1)
4825     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4826   mcIdType nbOfCells=getNumberOfCells();
4827   if(nbOfCells<1)
4828     return ;
4829   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4830   mcIdType *conn=_nodal_connec->getPointer();
4831   mcIdType *index=_nodal_connec_index->getPointer();
4832   mcIdType posOfCurCell=0;
4833   mcIdType newPos=0;
4834   mcIdType lgthOfCurCell;
4835   for(mcIdType i=0;i<nbOfCells;i++)
4836     {
4837       lgthOfCurCell=index[i+1]-posOfCurCell;
4838       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4839       mcIdType newLgth;
4840       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4841                                                                                                      conn+newPos+1,newLgth);
4842       conn[newPos]=newType;
4843       newPos+=newLgth+1;
4844       posOfCurCell=index[i+1];
4845       index[i+1]=newPos;
4846     }
4847   if(newPos!=initMeshLgth)
4848     _nodal_connec->reAlloc(newPos);
4849   computeTypes();
4850 }
4851
4852 /*!
4853  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4854  * A cell is flat in the following cases:
4855  *   - for a linear cell, all points in the connectivity are equal
4856  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4857  *   identical quadratic points
4858  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4859  *      this array using decrRef() as it is no more needed.
4860  */
4861 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4862 {
4863   checkFullyDefined();
4864   if(getMeshDimension()<=1)
4865     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4866   mcIdType nbOfCells=getNumberOfCells();
4867   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4868   if(nbOfCells<1)
4869     return ret.retn();
4870   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4871   mcIdType *conn=_nodal_connec->getPointer();
4872   mcIdType *index=_nodal_connec_index->getPointer();
4873   mcIdType posOfCurCell=0;
4874   mcIdType newPos=0;
4875   mcIdType lgthOfCurCell, nbDelCells(0);
4876   for(mcIdType i=0;i<nbOfCells;i++)
4877     {
4878       lgthOfCurCell=index[i+1]-posOfCurCell;
4879       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4880       mcIdType newLgth;
4881       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4882                                                                                                      conn+newPos+1,newLgth);
4883       // Shall we delete the cell if it is completely degenerated:
4884       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4885       if (delCell)
4886         {
4887           nbDelCells++;
4888           ret->pushBackSilent(i);
4889         }
4890       else   //if the cell is to be deleted, simply stay at the same place
4891         {
4892           conn[newPos]=newType;
4893           newPos+=newLgth+1;
4894         }
4895       posOfCurCell=index[i+1];
4896       index[i+1-nbDelCells]=newPos;
4897     }
4898   if(newPos!=initMeshLgth)
4899     _nodal_connec->reAlloc(newPos);
4900   const mcIdType nCellDel=ret->getNumberOfTuples();
4901   if (nCellDel)
4902     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4903   computeTypes();
4904   return ret.retn();
4905 }
4906
4907 /*!
4908  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4909  * Only connectivity is considered here.
4910  */
4911 bool MEDCouplingUMesh::removeDegenerated1DCells()
4912 {
4913   checkConnectivityFullyDefined();
4914   if(getMeshDimension()!=1)
4915     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4916   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4917   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4918   {
4919     for(std::size_t i=0;i<nbCells;i++)
4920       {
4921         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4922         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4923           {
4924             if(conn[conni[i]+1]!=conn[conni[i]+2])
4925               {
4926                 newSize++;
4927                 newSize2+=conni[i+1]-conni[i];
4928               }
4929           }
4930         else
4931           {
4932             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4933             throw INTERP_KERNEL::Exception(oss.str());
4934           }
4935       }
4936   }
4937   if(newSize==nbCells)//no cells has been removed -> do nothing
4938     return false;
4939   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4940   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4941   for(std::size_t i=0;i<nbCells;i++)
4942     {
4943       if(conn[conni[i]+1]!=conn[conni[i]+2])
4944         {
4945           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4946           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4947           newConnIPtr++;
4948         }
4949     }
4950   setConnectivity(newConn,newConnI,true);
4951   return true;
4952 }
4953
4954 /*!
4955  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4956  * A cell is considered to be oriented correctly if an angle between its
4957  * normal vector and a given vector is less than \c PI / \c 2.
4958  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4959  *         cells.
4960  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4961  *         checked.
4962  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4963  *         is not cleared before filling in.
4964  *  \throw If \a this->getMeshDimension() != 2.
4965  *  \throw If \a this->getSpaceDimension() != 3.
4966  *
4967  *  \if ENABLE_EXAMPLES
4968  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4969  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4970  *  \endif
4971  */
4972 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4973 {
4974   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4975     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4976   mcIdType nbOfCells=getNumberOfCells();
4977   const mcIdType *conn=_nodal_connec->begin();
4978   const mcIdType *connI=_nodal_connec_index->begin();
4979   const double *coordsPtr=_coords->begin();
4980   for(mcIdType i=0;i<nbOfCells;i++)
4981     {
4982       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4983       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4984         {
4985           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4986           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4987             cells.push_back(i);
4988         }
4989     }
4990 }
4991
4992 /*!
4993  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4994  * considered to be oriented correctly if an angle between its normal vector and a
4995  * given vector is less than \c PI / \c 2.
4996  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4997  *         cells.
4998  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4999  *         checked.
5000  *  \throw If \a this->getMeshDimension() != 2.
5001  *  \throw If \a this->getSpaceDimension() != 3.
5002  *
5003  *  \if ENABLE_EXAMPLES
5004  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5005  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5006  *  \endif
5007  *
5008  *  \sa changeOrientationOfCells
5009  */
5010 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5011 {
5012   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5013     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5014   mcIdType nbOfCells=getNumberOfCells();
5015   mcIdType *conn(_nodal_connec->getPointer());
5016   const mcIdType *connI(_nodal_connec_index->begin());
5017   const double *coordsPtr(_coords->begin());
5018   bool isModified(false);
5019   for(mcIdType i=0;i<nbOfCells;i++)
5020     {
5021       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5022       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5023         {
5024           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5025           bool isQuadratic(cm.isQuadratic());
5026           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5027             {
5028               isModified=true;
5029               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5030             }
5031         }
5032     }
5033   if(isModified)
5034     _nodal_connec->declareAsNew();
5035   updateTime();
5036 }
5037
5038 /*!
5039  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5040  *
5041  * \sa orientCorrectly2DCells
5042  */
5043 void MEDCouplingUMesh::changeOrientationOfCells()
5044 {
5045   int mdim(getMeshDimension());
5046   if(mdim!=2 && mdim!=1)
5047     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5048   mcIdType nbOfCells=getNumberOfCells();
5049   mcIdType *conn(_nodal_connec->getPointer());
5050   const mcIdType *connI(_nodal_connec_index->begin());
5051   if(mdim==2)
5052     {//2D
5053       for(mcIdType i=0;i<nbOfCells;i++)
5054         {
5055           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5056           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5057           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5058         }
5059     }
5060   else
5061     {//1D
5062       for(mcIdType i=0;i<nbOfCells;i++)
5063         {
5064           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5065           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5066           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5067         }
5068     }
5069 }
5070
5071 /*!
5072  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5073  * oriented facets. The normal vector of the facet should point out of the cell.
5074  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5075  *         is not cleared before filling in.
5076  *  \throw If \a this->getMeshDimension() != 3.
5077  *  \throw If \a this->getSpaceDimension() != 3.
5078  *  \throw If the coordinates array is not set.
5079  *  \throw If the nodal connectivity of cells is not defined.
5080  *
5081  *  \if ENABLE_EXAMPLES
5082  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5083  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5084  *  \endif
5085  */
5086 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5087 {
5088   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5089     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5090   mcIdType nbOfCells=getNumberOfCells();
5091   const mcIdType *conn=_nodal_connec->begin();
5092   const mcIdType *connI=_nodal_connec_index->begin();
5093   const double *coordsPtr=_coords->begin();
5094   for(mcIdType i=0;i<nbOfCells;i++)
5095     {
5096       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5097       if(type==INTERP_KERNEL::NORM_POLYHED)
5098         {
5099           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5100             cells.push_back(i);
5101         }
5102     }
5103 }
5104
5105 /*!
5106  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5107  * out of the cell.
5108  *  \throw If \a this->getMeshDimension() != 3.
5109  *  \throw If \a this->getSpaceDimension() != 3.
5110  *  \throw If the coordinates array is not set.
5111  *  \throw If the nodal connectivity of cells is not defined.
5112  *  \throw If the reparation fails.
5113  *
5114  *  \if ENABLE_EXAMPLES
5115  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5116  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5117  *  \endif
5118  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5119  */
5120 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5121 {
5122   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5123     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5124   mcIdType nbOfCells=getNumberOfCells();
5125   mcIdType *conn=_nodal_connec->getPointer();
5126   const mcIdType *connI=_nodal_connec_index->begin();
5127   const double *coordsPtr=_coords->begin();
5128   for(mcIdType i=0;i<nbOfCells;i++)
5129     {
5130       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5131       if(type==INTERP_KERNEL::NORM_POLYHED)
5132         {
5133           try
5134           {
5135               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5136                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5137           }
5138           catch(INTERP_KERNEL::Exception& e)
5139           {
5140               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5141               throw INTERP_KERNEL::Exception(oss.str());
5142           }
5143         }
5144     }
5145   updateTime();
5146 }
5147
5148 /*!
5149  * This method invert orientation of all cells in \a this.
5150  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5151  * This method only operates on the connectivity so coordinates are not touched at all.
5152  */
5153 void MEDCouplingUMesh::invertOrientationOfAllCells()
5154 {
5155   checkConnectivityFullyDefined();
5156   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5157   mcIdType *conn(_nodal_connec->getPointer());
5158   const mcIdType *conni(_nodal_connec_index->begin());
5159   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5160     {
5161       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5162       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5163       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5164         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5165     }
5166   updateTime();
5167 }
5168
5169 /*!
5170  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5171  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5172  * according to which the first facet of the cell should be oriented to have the normal vector
5173  * pointing out of cell.
5174  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5175  *         cells. The caller is to delete this array using decrRef() as it is no more
5176  *         needed.
5177  *  \throw If \a this->getMeshDimension() != 3.
5178  *  \throw If \a this->getSpaceDimension() != 3.
5179  *  \throw If the coordinates array is not set.
5180  *  \throw If the nodal connectivity of cells is not defined.
5181  *
5182  *  \if ENABLE_EXAMPLES
5183  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5184  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5185  *  \endif
5186  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5187  */
5188 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5189 {
5190   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5191   if(getMeshDimension()!=3)
5192     throw INTERP_KERNEL::Exception(msg);
5193   int spaceDim=getSpaceDimension();
5194   if(spaceDim!=3)
5195     throw INTERP_KERNEL::Exception(msg);
5196   //
5197   mcIdType nbOfCells=getNumberOfCells();
5198   mcIdType *conn=_nodal_connec->getPointer();
5199   const mcIdType *connI=_nodal_connec_index->begin();
5200   const double *coo=getCoords()->begin();
5201   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5202   for(mcIdType i=0;i<nbOfCells;i++)
5203     {
5204       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5205       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5206         {
5207           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5208             {
5209               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5210               cells->pushBackSilent(i);
5211             }
5212         }
5213     }
5214   return cells.retn();
5215 }
5216
5217 /*!
5218  * This method is a faster method to correct orientation of all 3D cells in \a this.
5219  * 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.
5220  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5221  *
5222  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5223  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5224  */
5225 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5226 {
5227   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5228     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5229   mcIdType nbOfCells=getNumberOfCells();
5230   mcIdType *conn=_nodal_connec->getPointer();
5231   const mcIdType *connI=_nodal_connec_index->begin();
5232   const double *coordsPtr=_coords->begin();
5233   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5234   for(mcIdType i=0;i<nbOfCells;i++)
5235     {
5236       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5237       switch(type)
5238       {
5239         case INTERP_KERNEL::NORM_TETRA4:
5240           {
5241             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5242               {
5243                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5244                 ret->pushBackSilent(i);
5245               }
5246             break;
5247           }
5248         case INTERP_KERNEL::NORM_PYRA5:
5249           {
5250             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5251               {
5252                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5253                 ret->pushBackSilent(i);
5254               }
5255             break;
5256           }
5257         case INTERP_KERNEL::NORM_PENTA6:
5258         case INTERP_KERNEL::NORM_HEXA8:
5259         case INTERP_KERNEL::NORM_HEXGP12:
5260           {
5261             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5262               {
5263                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5264                 ret->pushBackSilent(i);
5265               }
5266             break;
5267           }
5268         case INTERP_KERNEL::NORM_POLYHED:
5269           {
5270             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5271               {
5272                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5273                 ret->pushBackSilent(i);
5274               }
5275             break;
5276           }
5277         default:
5278           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 !");
5279       }
5280     }
5281   updateTime();
5282   return ret.retn();
5283 }
5284
5285 /*!
5286  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5287  * If it is not the case an exception will be thrown.
5288  * This method is fast because the first cell of \a this is used to compute the plane.
5289  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5290  * \param pos output of size at least 3 used to store a point owned of searched plane.
5291  */
5292 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5293 {
5294   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5295     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5296   const mcIdType *conn=_nodal_connec->begin();
5297   const mcIdType *connI=_nodal_connec_index->begin();
5298   const double *coordsPtr=_coords->begin();
5299   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5300   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5301 }
5302
5303 /*!
5304  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5305  * cells. Currently cells of the following types are treated:
5306  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5307  * For a cell of other type an exception is thrown.
5308  * Space dimension of a 2D mesh can be either 2 or 3.
5309  * The Edge Ratio of a cell \f$t\f$ is:
5310  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5311  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5312  *  the smallest edge lengths of \f$t\f$.
5313  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5314  *          cells and one time, lying on \a this mesh. The caller is to delete this
5315  *          field using decrRef() as it is no more needed.
5316  *  \throw If the coordinates array is not set.
5317  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5318  *  \throw If the connectivity data array has more than one component.
5319  *  \throw If the connectivity data array has a named component.
5320  *  \throw If the connectivity index data array has more than one component.
5321  *  \throw If the connectivity index data array has a named component.
5322  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5323  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5324  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5325  */
5326 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5327 {
5328   checkConsistencyLight();
5329   int spaceDim=getSpaceDimension();
5330   int meshDim=getMeshDimension();
5331   if(spaceDim!=2 && spaceDim!=3)
5332     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5333   if(meshDim!=2 && meshDim!=3)
5334     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5335   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5336   ret->setMesh(this);
5337   mcIdType nbOfCells=getNumberOfCells();
5338   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5339   arr->alloc(nbOfCells,1);
5340   double *pt=arr->getPointer();
5341   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5342   const mcIdType *conn=_nodal_connec->begin();
5343   const mcIdType *connI=_nodal_connec_index->begin();
5344   const double *coo=_coords->begin();
5345   double tmp[12];
5346   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5347     {
5348       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5349       switch(t)
5350       {
5351         case INTERP_KERNEL::NORM_TRI3:
5352           {
5353             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5354             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5355             break;
5356           }
5357         case INTERP_KERNEL::NORM_QUAD4:
5358           {
5359             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5360             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5361             break;
5362           }
5363         case INTERP_KERNEL::NORM_TETRA4:
5364           {
5365             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5366             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5367             break;
5368           }
5369         default:
5370           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5371       }
5372       conn+=connI[i+1]-connI[i];
5373     }
5374   ret->setName("EdgeRatio");
5375   ret->synchronizeTimeWithSupport();
5376   return ret.retn();
5377 }
5378
5379 /*!
5380  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5381  * cells. Currently cells of the following types are treated:
5382  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5383  * For a cell of other type an exception is thrown.
5384  * Space dimension of a 2D mesh can be either 2 or 3.
5385  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5386  *          cells and one time, lying on \a this mesh. The caller is to delete this
5387  *          field using decrRef() as it is no more needed.
5388  *  \throw If the coordinates array is not set.
5389  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5390  *  \throw If the connectivity data array has more than one component.
5391  *  \throw If the connectivity data array has a named component.
5392  *  \throw If the connectivity index data array has more than one component.
5393  *  \throw If the connectivity index data array has a named component.
5394  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5395  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5396  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5397  */
5398 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5399 {
5400   checkConsistencyLight();
5401   int spaceDim=getSpaceDimension();
5402   int meshDim=getMeshDimension();
5403   if(spaceDim!=2 && spaceDim!=3)
5404     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5405   if(meshDim!=2 && meshDim!=3)
5406     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5407   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5408   ret->setMesh(this);
5409   mcIdType nbOfCells=getNumberOfCells();
5410   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5411   arr->alloc(nbOfCells,1);
5412   double *pt=arr->getPointer();
5413   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5414   const mcIdType *conn=_nodal_connec->begin();
5415   const mcIdType *connI=_nodal_connec_index->begin();
5416   const double *coo=_coords->begin();
5417   double tmp[12];
5418   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5419     {
5420       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5421       switch(t)
5422       {
5423         case INTERP_KERNEL::NORM_TRI3:
5424           {
5425             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5426             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5427             break;
5428           }
5429         case INTERP_KERNEL::NORM_QUAD4:
5430           {
5431             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5432             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5433             break;
5434           }
5435         case INTERP_KERNEL::NORM_TETRA4:
5436           {
5437             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5438             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5439             break;
5440           }
5441         default:
5442           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5443       }
5444       conn+=connI[i+1]-connI[i];
5445     }
5446   ret->setName("AspectRatio");
5447   ret->synchronizeTimeWithSupport();
5448   return ret.retn();
5449 }
5450
5451 /*!
5452  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5453  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5454  * in 3D space. Currently only cells of the following types are
5455  * treated: INTERP_KERNEL::NORM_QUAD4.
5456  * For a cell of other type an exception is thrown.
5457  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5458  * Defining
5459  * \f$t=\vec{da}\times\vec{ab}\f$,
5460  * \f$u=\vec{ab}\times\vec{bc}\f$
5461  * \f$v=\vec{bc}\times\vec{cd}\f$
5462  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5463  *  \f[
5464  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5465  *  \f]
5466  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5467  *          cells and one time, lying on \a this mesh. The caller is to delete this
5468  *          field using decrRef() as it is no more needed.
5469  *  \throw If the coordinates array is not set.
5470  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5471  *  \throw If the connectivity data array has more than one component.
5472  *  \throw If the connectivity data array has a named component.
5473  *  \throw If the connectivity index data array has more than one component.
5474  *  \throw If the connectivity index data array has a named component.
5475  *  \throw If \a this->getMeshDimension() != 2.
5476  *  \throw If \a this->getSpaceDimension() != 3.
5477  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5478  */
5479 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5480 {
5481   checkConsistencyLight();
5482   int spaceDim=getSpaceDimension();
5483   int meshDim=getMeshDimension();
5484   if(spaceDim!=3)
5485     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5486   if(meshDim!=2)
5487     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5488   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5489   ret->setMesh(this);
5490   mcIdType nbOfCells=getNumberOfCells();
5491   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5492   arr->alloc(nbOfCells,1);
5493   double *pt=arr->getPointer();
5494   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5495   const mcIdType *conn=_nodal_connec->begin();
5496   const mcIdType *connI=_nodal_connec_index->begin();
5497   const double *coo=_coords->begin();
5498   double tmp[12];
5499   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5500     {
5501       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5502       switch(t)
5503       {
5504         case INTERP_KERNEL::NORM_QUAD4:
5505           {
5506             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5507             *pt=INTERP_KERNEL::quadWarp(tmp);
5508             break;
5509           }
5510         default:
5511           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5512       }
5513       conn+=connI[i+1]-connI[i];
5514     }
5515   ret->setName("Warp");
5516   ret->synchronizeTimeWithSupport();
5517   return ret.retn();
5518 }
5519
5520
5521 /*!
5522  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5523  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5524  * treated: INTERP_KERNEL::NORM_QUAD4.
5525  * The skew is computed as follow for a quad with points (a,b,c,d): let
5526  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5527  * then the skew is computed as:
5528  *  \f[
5529  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5530  *  \f]
5531  *
5532  * For a cell of other type an exception is thrown.
5533  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5534  *          cells and one time, lying on \a this mesh. The caller is to delete this
5535  *          field using decrRef() as it is no more needed.
5536  *  \throw If the coordinates array is not set.
5537  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5538  *  \throw If the connectivity data array has more than one component.
5539  *  \throw If the connectivity data array has a named component.
5540  *  \throw If the connectivity index data array has more than one component.
5541  *  \throw If the connectivity index data array has a named component.
5542  *  \throw If \a this->getMeshDimension() != 2.
5543  *  \throw If \a this->getSpaceDimension() != 3.
5544  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5545  */
5546 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5547 {
5548   checkConsistencyLight();
5549   int spaceDim=getSpaceDimension();
5550   int meshDim=getMeshDimension();
5551   if(spaceDim!=3)
5552     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5553   if(meshDim!=2)
5554     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5555   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5556   ret->setMesh(this);
5557   mcIdType nbOfCells=getNumberOfCells();
5558   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5559   arr->alloc(nbOfCells,1);
5560   double *pt=arr->getPointer();
5561   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5562   const mcIdType *conn=_nodal_connec->begin();
5563   const mcIdType *connI=_nodal_connec_index->begin();
5564   const double *coo=_coords->begin();
5565   double tmp[12];
5566   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5567     {
5568       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5569       switch(t)
5570       {
5571         case INTERP_KERNEL::NORM_QUAD4:
5572           {
5573             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5574             *pt=INTERP_KERNEL::quadSkew(tmp);
5575             break;
5576           }
5577         default:
5578           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5579       }
5580       conn+=connI[i+1]-connI[i];
5581     }
5582   ret->setName("Skew");
5583   ret->synchronizeTimeWithSupport();
5584   return ret.retn();
5585 }
5586
5587 /*!
5588  * 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.
5589  *
5590  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5591  *
5592  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5593  */
5594 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5595 {
5596   checkConsistencyLight();
5597   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5598   ret->setMesh(this);
5599   std::set<INTERP_KERNEL::NormalizedCellType> types;
5600   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5601   int spaceDim(getSpaceDimension());
5602   mcIdType nbCells(getNumberOfCells());
5603   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5604   arr->alloc(nbCells,1);
5605   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5606     {
5607       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5608       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5609       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5610     }
5611   ret->setArray(arr);
5612   ret->setName("Diameter");
5613   return ret.retn();
5614 }
5615
5616 /*!
5617  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5618  *
5619  * \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)
5620  *                         For all other cases this input parameter is ignored.
5621  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5622  *
5623  * \throw If \a this is not fully set (coordinates and connectivity).
5624  * \throw If a cell in \a this has no valid nodeId.
5625  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5626  */
5627 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5628 {
5629   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5630   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.
5631     return getBoundingBoxForBBTreeFast();
5632   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5633     {
5634       bool presenceOfQuadratic(false);
5635       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5636         {
5637           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5638           if(cm.isQuadratic())
5639             presenceOfQuadratic=true;
5640         }
5641       if(!presenceOfQuadratic)
5642         return getBoundingBoxForBBTreeFast();
5643       if(mDim==2 && sDim==2)
5644         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5645       else
5646         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5647     }
5648   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) !");
5649 }
5650
5651 /*!
5652  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5653  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5654  *
5655  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5656  *
5657  * \throw If \a this is not fully set (coordinates and connectivity).
5658  * \throw If a cell in \a this has no valid nodeId.
5659  */
5660 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5661 {
5662   checkFullyDefined();
5663   int spaceDim(getSpaceDimension());
5664   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5665   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5666   double *bbox(ret->getPointer());
5667   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5668     {
5669       bbox[2*i]=std::numeric_limits<double>::max();
5670       bbox[2*i+1]=-std::numeric_limits<double>::max();
5671     }
5672   const double *coordsPtr(_coords->begin());
5673   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5674   for(mcIdType i=0;i<nbOfCells;i++)
5675     {
5676       mcIdType offset=connI[i]+1;
5677       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5678       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5679         {
5680           mcIdType nodeId=conn[offset+j];
5681           if(nodeId>=0 && nodeId<nbOfNodes)
5682             {
5683               for(int k=0;k<spaceDim;k++)
5684                 {
5685                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5686                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5687                 }
5688               kk++;
5689             }
5690         }
5691       if(kk==0)
5692         {
5693           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5694           throw INTERP_KERNEL::Exception(oss.str());
5695         }
5696     }
5697   return ret.retn();
5698 }
5699
5700 /*!
5701  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5702  * useful for 2D meshes having quadratic cells
5703  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5704  * the two extremities of the arc of circle).
5705  *
5706  * \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)
5707  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5708  * \throw If \a this is not fully defined.
5709  * \throw If \a this is not a mesh with meshDimension equal to 2.
5710  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5711  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5712  */
5713 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5714 {
5715   checkFullyDefined();
5716   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5717
5718   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5719   mcIdType nbOfCells=getNumberOfCells();
5720   if(spaceDim!=2 || mDim!=2)
5721     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!");
5722   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5723   double *bbox(ret->getPointer());
5724   const double *coords(_coords->begin());
5725   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5726   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5727     {
5728       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5729       mcIdType sz(connI[1]-connI[0]-1);
5730       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5731       INTERP_KERNEL::QuadraticPolygon *pol(0);
5732       for(mcIdType j=0;j<sz;j++)
5733         {
5734           mcIdType nodeId(conn[*connI+1+j]);
5735           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5736         }
5737       if(!cm.isQuadratic())
5738         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5739       else
5740         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5741       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5742       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5743     }
5744   return ret.retn();
5745 }
5746
5747 /*!
5748  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5749  * useful for 2D meshes having quadratic cells
5750  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5751  * the two extremities of the arc of circle).
5752  *
5753  * \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)
5754  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5755  * \throw If \a this is not fully defined.
5756  * \throw If \a this is not a mesh with meshDimension equal to 1.
5757  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5758  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5759  */
5760 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5761 {
5762   checkFullyDefined();
5763   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5764   mcIdType nbOfCells=getNumberOfCells();
5765   if(spaceDim!=2 || mDim!=1)
5766     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!");
5767   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5768   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5769   double *bbox(ret->getPointer());
5770   const double *coords(_coords->begin());
5771   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5772   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5773     {
5774       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5775       mcIdType sz(connI[1]-connI[0]-1);
5776       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5777       INTERP_KERNEL::Edge *edge(0);
5778       for(mcIdType j=0;j<sz;j++)
5779         {
5780           mcIdType nodeId(conn[*connI+1+j]);
5781           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5782         }
5783       if(!cm.isQuadratic())
5784         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5785       else
5786         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5787       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5788       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5789     }
5790   return ret.retn();
5791 }
5792
5793 /// @cond INTERNAL
5794
5795 namespace MEDCouplingImpl
5796 {
5797   class ConnReader
5798   {
5799   public:
5800     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5801     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5802   private:
5803     const mcIdType *_conn;
5804     mcIdType _val;
5805   };
5806
5807   class ConnReader2
5808   {
5809   public:
5810     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5811     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5812   private:
5813     const mcIdType *_conn;
5814     mcIdType _val;
5815   };
5816 }
5817
5818 /// @endcond
5819
5820 /*!
5821  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5822  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5823  * \a this is composed in cell types.
5824  * The returned array is of size 3*n where n is the number of different types present in \a this.
5825  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5826  * This parameter is kept only for compatibility with other method listed above.
5827  */
5828 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5829 {
5830   checkConnectivityFullyDefined();
5831   const mcIdType *conn=_nodal_connec->begin();
5832   const mcIdType *connI=_nodal_connec_index->begin();
5833   const mcIdType *work=connI;
5834   mcIdType nbOfCells=getNumberOfCells();
5835   std::size_t n=getAllGeoTypes().size();
5836   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5837   std::set<INTERP_KERNEL::NormalizedCellType> types;
5838   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5839     {
5840       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5841       if(types.find(typ)!=types.end())
5842         {
5843           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5844           oss << " is not contiguous !";
5845           throw INTERP_KERNEL::Exception(oss.str());
5846         }
5847       types.insert(typ);
5848       ret[3*i]=typ;
5849       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5850       ret[3*i+1]=ToIdType(std::distance(work,work2));
5851       work=work2;
5852     }
5853   return ret;
5854 }
5855
5856 /*!
5857  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5858  * only for types cell, type node is not managed.
5859  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5860  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5861  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5862  * If 2 or more same geometric type is in \a code and exception is thrown too.
5863  *
5864  * This method firstly checks
5865  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5866  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5867  * an exception is thrown too.
5868  *
5869  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5870  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5871  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5872  */
5873 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5874 {
5875   if(code.empty())
5876     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5877   std::size_t sz=code.size();
5878   std::size_t n=sz/3;
5879   if(sz%3!=0)
5880     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5881   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5882   mcIdType nb=0;
5883   bool isNoPflUsed=true;
5884   for(std::size_t i=0;i<n;i++)
5885     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5886       {
5887         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5888         nb+=code[3*i+1];
5889         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5890           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5891         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5892       }
5893   if(types.size()!=n)
5894     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5895   if(isNoPflUsed)
5896     {
5897       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5898         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5899       if(types.size()==_types.size())
5900         return 0;
5901     }
5902   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5903   ret->alloc(nb,1);
5904   mcIdType *retPtr=ret->getPointer();
5905   const mcIdType *connI=_nodal_connec_index->begin();
5906   const mcIdType *conn=_nodal_connec->begin();
5907   mcIdType nbOfCells=getNumberOfCells();
5908   const mcIdType *i=connI;
5909   int kk=0;
5910   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5911     {
5912       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5913       mcIdType offset=ToIdType(std::distance(connI,i));
5914       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5915       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5916       if(code[3*kk+2]==-1)
5917         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5918           *retPtr++=k+offset;
5919       else
5920         {
5921           mcIdType idInIdsPerType=code[3*kk+2];
5922           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5923             {
5924               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5925               if(zePfl)
5926                 {
5927                   zePfl->checkAllocated();
5928                   if(zePfl->getNumberOfComponents()==1)
5929                     {
5930                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5931                         {
5932                           if(*k>=0 && *k<nbOfCellsOfCurType)
5933                             *retPtr=(*k)+offset;
5934                           else
5935                             {
5936                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5937                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5938                               throw INTERP_KERNEL::Exception(oss.str());
5939                             }
5940                         }
5941                     }
5942                   else
5943                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5944                 }
5945               else
5946                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5947             }
5948           else
5949             {
5950               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5951               oss << " should be in [0," << idsPerType.size() << ") !";
5952               throw INTERP_KERNEL::Exception(oss.str());
5953             }
5954         }
5955       i=j;
5956     }
5957   return ret.retn();
5958 }
5959
5960 /*!
5961  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5962  * 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.
5963  * 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.
5964  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5965  *
5966  * \param [in] profile list of IDs constituing the profile
5967  * \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.
5968  * \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,
5969  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5970  * \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.
5971  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5972  * \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
5973  */
5974 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5975 {
5976   if(!profile)
5977     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5978   if(profile->getNumberOfComponents()!=1)
5979     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5980   checkConnectivityFullyDefined();
5981   const mcIdType *conn=_nodal_connec->begin();
5982   const mcIdType *connI=_nodal_connec_index->begin();
5983   mcIdType nbOfCells=getNumberOfCells();
5984   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5985   std::vector<mcIdType> typeRangeVals(1);
5986   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5987     {
5988       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5989       if(std::find(types.begin(),types.end(),curType)!=types.end())
5990         {
5991           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5992         }
5993       types.push_back(curType);
5994       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5995       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5996     }
5997   //
5998   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5999   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6000   MCAuto<DataArrayIdType> tmp0=castArr;
6001   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6002   MCAuto<DataArrayIdType> tmp2=castsPresent;
6003   //
6004   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6005   code.resize(3*nbOfCastsFinal);
6006   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6007   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6008   for(mcIdType i=0;i<nbOfCastsFinal;i++)
6009     {
6010       mcIdType castId=castsPresent->getIJ(i,0);
6011       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6012       idsInPflPerType2.push_back(tmp3);
6013       code[3*i]=ToIdType(types[castId]);
6014       code[3*i+1]=tmp3->getNumberOfTuples();
6015       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6016       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6017         {
6018           tmp4->copyStringInfoFrom(*profile);
6019           idsPerType2.push_back(tmp4);
6020           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6021         }
6022       else
6023         {
6024           code[3*i+2]=-1;
6025         }
6026     }
6027   std::size_t sz2=idsInPflPerType2.size();
6028   idsInPflPerType.resize(sz2);
6029   for(std::size_t i=0;i<sz2;i++)
6030     {
6031       DataArrayIdType *locDa=idsInPflPerType2[i];
6032       locDa->incrRef();
6033       idsInPflPerType[i]=locDa;
6034     }
6035   std::size_t sz=idsPerType2.size();
6036   idsPerType.resize(sz);
6037   for(std::size_t i=0;i<sz;i++)
6038     {
6039       DataArrayIdType *locDa=idsPerType2[i];
6040       locDa->incrRef();
6041       idsPerType[i]=locDa;
6042     }
6043 }
6044
6045 /*!
6046  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6047  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6048  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6049  * 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.
6050  */
6051 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6052 {
6053   checkFullyDefined();
6054   nM1LevMesh->checkFullyDefined();
6055   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6056     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6057   if(_coords!=nM1LevMesh->getCoords())
6058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6059   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6060   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6061   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6062   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6063   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6064   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6065   tmp->setConnectivity(tmp0,tmp1);
6066   tmp->renumberCells(ret0->begin(),false);
6067   revDesc=tmp->getNodalConnectivity();
6068   revDescIndx=tmp->getNodalConnectivityIndex();
6069   DataArrayIdType *ret=0;
6070   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6071     {
6072       mcIdType tmp2;
6073       ret->getMaxValue(tmp2);
6074       ret->decrRef();
6075       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6076       throw INTERP_KERNEL::Exception(oss.str());
6077     }
6078   nM1LevMeshIds=ret;
6079   //
6080   revDesc->incrRef();
6081   revDescIndx->incrRef();
6082   ret1->incrRef();
6083   ret0->incrRef();
6084   meshnM1Old2New=ret0;
6085   return ret1;
6086 }
6087
6088 /*!
6089  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6090  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6091  * in "Old to New" mode.
6092  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6093  *          this array using decrRef() as it is no more needed.
6094  *  \throw If the nodal connectivity of cells is not defined.
6095  */
6096 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6097 {
6098   checkConnectivityFullyDefined();
6099   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6100   renumberCells(ret->begin(),false);
6101   return ret.retn();
6102 }
6103
6104 /*!
6105  * This methods checks that cells are sorted by their types.
6106  * This method makes asumption (no check) that connectivity is correctly set before calling.
6107  */
6108 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6109 {
6110   checkFullyDefined();
6111   const mcIdType *conn=_nodal_connec->begin();
6112   const mcIdType *connI=_nodal_connec_index->begin();
6113   mcIdType nbOfCells=getNumberOfCells();
6114   std::set<INTERP_KERNEL::NormalizedCellType> types;
6115   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6116     {
6117       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6118       if(types.find(curType)!=types.end())
6119         return false;
6120       types.insert(curType);
6121       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6122     }
6123   return true;
6124 }
6125
6126 /*!
6127  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6128  * The geometric type order is specified by MED file.
6129  *
6130  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6131  */
6132 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6133 {
6134   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6135 }
6136
6137 /*!
6138  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6139  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6140  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6141  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6142  */
6143 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6144 {
6145   checkFullyDefined();
6146   const mcIdType *conn=_nodal_connec->begin();
6147   const mcIdType *connI=_nodal_connec_index->begin();
6148   mcIdType nbOfCells=getNumberOfCells();
6149   if(nbOfCells==0)
6150     return true;
6151   mcIdType lastPos=-1;
6152   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6153   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6154     {
6155       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6156       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6157       if(isTypeExists!=orderEnd)
6158         {
6159           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6160           if(pos<=lastPos)
6161             return false;
6162           lastPos=pos;
6163           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6164         }
6165       else
6166         {
6167           if(sg.find(curType)==sg.end())
6168             {
6169               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6170               sg.insert(curType);
6171             }
6172           else
6173             return false;
6174         }
6175     }
6176   return true;
6177 }
6178
6179 /*!
6180  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6181  * 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
6182  * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurrence of type in 'this'.
6183  */
6184 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6185 {
6186   checkConnectivityFullyDefined();
6187   mcIdType nbOfCells=getNumberOfCells();
6188   const mcIdType *conn=_nodal_connec->begin();
6189   const mcIdType *connI=_nodal_connec_index->begin();
6190   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6191   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6192   tmpa->alloc(nbOfCells,1);
6193   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6194   tmpb->fillWithZero();
6195   mcIdType *tmp=tmpa->getPointer();
6196   mcIdType *tmp2=tmpb->getPointer();
6197   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6198     {
6199       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6200       if(where!=orderEnd)
6201         {
6202           mcIdType pos=ToIdType(std::distance(orderBg,where));
6203           tmp2[pos]++;
6204           tmp[std::distance(connI,i)]=pos;
6205         }
6206       else
6207         {
6208           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6209           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6210           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6211           throw INTERP_KERNEL::Exception(oss.str());
6212         }
6213     }
6214   nbPerType=tmpb.retn();
6215   return tmpa.retn();
6216 }
6217
6218 /*!
6219  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6220  *
6221  * \return a new object containing the old to new correspondence.
6222  *
6223  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6224  */
6225 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6226 {
6227   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6228 }
6229
6230 /*!
6231  * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specified by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
6232  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6233  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6234  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6235  */
6236 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6237 {
6238   DataArrayIdType *nbPerType=0;
6239   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6240   nbPerType->decrRef();
6241   return tmpa->buildPermArrPerLevel();
6242 }
6243
6244 /*!
6245  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6246  * The number of cells remains unchanged after the call of this method.
6247  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6248  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6249  *
6250  * \return the array giving the correspondence old to new.
6251  */
6252 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6253 {
6254   checkFullyDefined();
6255   computeTypes();
6256   const mcIdType *conn=_nodal_connec->begin();
6257   const mcIdType *connI=_nodal_connec_index->begin();
6258   mcIdType nbOfCells=getNumberOfCells();
6259   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6260   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6261     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6262       {
6263         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6264         types.push_back(curType);
6265         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6266       }
6267   DataArrayIdType *ret=DataArrayIdType::New();
6268   ret->alloc(nbOfCells,1);
6269   mcIdType *retPtr=ret->getPointer();
6270   std::fill(retPtr,retPtr+nbOfCells,-1);
6271   mcIdType newCellId=0;
6272   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6273     {
6274       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6275         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6276           retPtr[std::distance(connI,i)]=newCellId++;
6277     }
6278   renumberCells(retPtr,false);
6279   return ret;
6280 }
6281
6282 /*!
6283  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6284  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6285  * This method makes asumption that connectivity is correctly set before calling.
6286  */
6287 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6288 {
6289   checkConnectivityFullyDefined();
6290   const mcIdType *conn=_nodal_connec->begin();
6291   const mcIdType *connI=_nodal_connec_index->begin();
6292   mcIdType nbOfCells=getNumberOfCells();
6293   std::vector<MEDCouplingUMesh *> ret;
6294   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6295     {
6296       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6297       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6298       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6299       mcIdType endCellId=ToIdType(std::distance(connI,i));
6300       mcIdType sz=endCellId-beginCellId;
6301       mcIdType *cells=new mcIdType[sz];
6302       for(mcIdType j=0;j<sz;j++)
6303         cells[j]=beginCellId+j;
6304       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6305       delete [] cells;
6306       ret.push_back(m);
6307     }
6308   return ret;
6309 }
6310
6311 /*!
6312  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6313  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6314  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6315  *
6316  * \return a newly allocated instance, that the caller must manage.
6317  * \throw If \a this contains more than one geometric type.
6318  * \throw If the nodal connectivity of \a this is not fully defined.
6319  * \throw If the internal data is not coherent.
6320  */
6321 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6322 {
6323   checkConnectivityFullyDefined();
6324   if(_types.size()!=1)
6325     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6326   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6327   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6328   ret->setCoords(getCoords());
6329   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6330   if(retC)
6331     {
6332       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6333       retC->setNodalConnectivity(c);
6334     }
6335   else
6336     {
6337       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6338       if(!retD)
6339         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6340       DataArrayIdType *c=0,*ci=0;
6341       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6342       MCAuto<DataArrayIdType> cs(c),cis(ci);
6343       retD->setNodalConnectivity(cs,cis);
6344     }
6345   return ret.retn();
6346 }
6347
6348 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6349 {
6350   checkConnectivityFullyDefined();
6351   if(_types.size()!=1)
6352     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6353   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6354   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6355   if(cm.isDynamic())
6356     {
6357       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6358       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6359       throw INTERP_KERNEL::Exception(oss.str());
6360     }
6361   mcIdType nbCells=getNumberOfCells();
6362   mcIdType typi=ToIdType(typ);
6363   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6364   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6365   mcIdType *outPtr=connOut->getPointer();
6366   const mcIdType *conn=_nodal_connec->begin();
6367   const mcIdType *connI=_nodal_connec_index->begin();
6368   nbNodesPerCell++;
6369   for(mcIdType i=0;i<nbCells;i++,connI++)
6370     {
6371       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6372         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6373       else
6374         {
6375           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 << ") !";
6376           throw INTERP_KERNEL::Exception(oss.str());
6377         }
6378     }
6379   return connOut.retn();
6380 }
6381
6382 /*!
6383  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6384  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6385  * \param nodalConn nodal connectivity
6386  * \param nodalConnIndex nodal connectivity indices
6387  */
6388 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6389 {
6390   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6391   checkConnectivityFullyDefined();
6392   if(_types.size()!=1)
6393     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6394   mcIdType nbCells=getNumberOfCells(),
6395            lgth=_nodal_connec->getNumberOfTuples();
6396   if(lgth<nbCells)
6397     throw INTERP_KERNEL::Exception(msg0);
6398   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6399   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6400   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6401   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6402   cip[0]=0;
6403   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6404     {
6405       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6406       mcIdType delta(stop-strt);
6407       if(delta>=1)
6408         {
6409           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6410             cp=std::copy(incp+strt,incp+stop,cp);
6411           else
6412             throw INTERP_KERNEL::Exception(msg0);
6413         }
6414       else
6415         throw INTERP_KERNEL::Exception(msg0);
6416       cip[1]=cip[0]+delta;
6417     }
6418   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6419 }
6420
6421 /*!
6422  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6423  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6424  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6425  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6426  * are not used here to avoid the build of big permutation array.
6427  *
6428  * \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
6429  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6430  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6431  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6432  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6433  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6434  * \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
6435  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6436  */
6437 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6438                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6439                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6440 {
6441   std::vector<const MEDCouplingUMesh *> ms2;
6442   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6443     if(*it)
6444       {
6445         (*it)->checkConnectivityFullyDefined();
6446         ms2.push_back(*it);
6447       }
6448   if(ms2.empty())
6449     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6450   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6451   int meshDim=ms2[0]->getMeshDimension();
6452   std::vector<const MEDCouplingUMesh *> m1ssm;
6453   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6454   //
6455   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6456   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6457   mcIdType fake=0,rk=0;
6458   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6459   ret1->alloc(0,1); ret2->alloc(0,1);
6460   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6461     {
6462       if(meshDim!=(*it)->getMeshDimension())
6463         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6464       if(refCoo!=(*it)->getCoords())
6465         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6466       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6467       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6468       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6469       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6470         {
6471           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6472           m1ssmSingleAuto.push_back(singleCell);
6473           m1ssmSingle.push_back(singleCell);
6474           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6475         }
6476     }
6477   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6478   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6479   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6480   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6481     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6482   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6483   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6484   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6485   return ret0.retn();
6486 }
6487
6488 /*!
6489  * This method returns a newly created DataArrayIdType instance.
6490  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6491  */
6492 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6493 {
6494   checkFullyDefined();
6495   const mcIdType *conn=_nodal_connec->begin();
6496   const mcIdType *connIndex=_nodal_connec_index->begin();
6497   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6498   for(const mcIdType *w=begin;w!=end;w++)
6499     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6500       ret->pushBackSilent(*w);
6501   return ret.retn();
6502 }
6503
6504 /*!
6505  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6506  * are in [0:getNumberOfCells())
6507  */
6508 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6509 {
6510   checkFullyDefined();
6511   const mcIdType *conn=_nodal_connec->begin();
6512   const mcIdType *connI=_nodal_connec_index->begin();
6513   mcIdType nbOfCells=getNumberOfCells();
6514   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6515   mcIdType *tmp=new mcIdType[nbOfCells];
6516   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6517     {
6518       mcIdType j=0;
6519       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6520         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6521           tmp[std::distance(connI,i)]=j++;
6522     }
6523   DataArrayIdType *ret=DataArrayIdType::New();
6524   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6525   ret->copyStringInfoFrom(*da);
6526   mcIdType *retPtr=ret->getPointer();
6527   const mcIdType *daPtr=da->begin();
6528   mcIdType nbOfElems=da->getNbOfElems();
6529   for(mcIdType k=0;k<nbOfElems;k++)
6530     retPtr[k]=tmp[daPtr[k]];
6531   delete [] tmp;
6532   return ret;
6533 }
6534
6535 /*!
6536  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6537  * This method \b works \b for mesh sorted by type.
6538  * cells whose ids is in 'idsPerGeoType' array.
6539  * This method conserves coords and name of mesh.
6540  */
6541 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6542 {
6543   std::vector<mcIdType> code=getDistributionOfTypes();
6544   std::size_t nOfTypesInThis=code.size()/3;
6545   mcIdType sz=0,szOfType=0;
6546   for(std::size_t i=0;i<nOfTypesInThis;i++)
6547     {
6548       if(code[3*i]!=type)
6549         sz+=code[3*i+1];
6550       else
6551         szOfType=code[3*i+1];
6552     }
6553   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6554     if(*work<0 || *work>=szOfType)
6555       {
6556         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6557         oss << ". It should be in [0," << szOfType << ") !";
6558         throw INTERP_KERNEL::Exception(oss.str());
6559       }
6560   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6561   mcIdType *idsPtr=idsTokeep->getPointer();
6562   mcIdType offset=0;
6563   for(std::size_t i=0;i<nOfTypesInThis;i++)
6564     {
6565       if(code[3*i]!=type)
6566         for(mcIdType j=0;j<code[3*i+1];j++)
6567           *idsPtr++=offset+j;
6568       else
6569         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6570       offset+=code[3*i+1];
6571     }
6572   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6573   ret->copyTinyInfoFrom(this);
6574   return ret.retn();
6575 }
6576
6577 /*!
6578  * This method returns a vector of size 'this->getNumberOfCells()'.
6579  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6580  */
6581 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6582 {
6583   mcIdType ncell=getNumberOfCells();
6584   std::vector<bool> ret(ncell);
6585   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6586   const mcIdType *c=getNodalConnectivity()->begin();
6587   for(mcIdType i=0;i<ncell;i++)
6588     {
6589       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6590       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6591       ret[i]=cm.isQuadratic();
6592     }
6593   return ret;
6594 }
6595
6596 /*!
6597  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6598  */
6599 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6600 {
6601   if(other->getType()!=UNSTRUCTURED)
6602     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6603   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6604   return MergeUMeshes(this,otherC);
6605 }
6606
6607 /*!
6608  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6609  * computed by averaging coordinates of cell nodes, so this method is not a right
6610  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6611  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6612  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6613  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6614  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6615  *          components. The caller is to delete this array using decrRef() as it is
6616  *          no more needed.
6617  *  \throw If the coordinates array is not set.
6618  *  \throw If the nodal connectivity of cells is not defined.
6619  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6620  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6621  */
6622 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6623 {
6624   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6625   int spaceDim=getSpaceDimension();
6626   mcIdType nbOfCells=getNumberOfCells();
6627   ret->alloc(nbOfCells,spaceDim);
6628   ret->copyStringInfoFrom(*getCoords());
6629   double *ptToFill=ret->getPointer();
6630   const mcIdType *nodal=_nodal_connec->begin();
6631   const mcIdType *nodalI=_nodal_connec_index->begin();
6632   const double *coor=_coords->begin();
6633   for(mcIdType i=0;i<nbOfCells;i++)
6634     {
6635       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6636       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6637       ptToFill+=spaceDim;
6638     }
6639   return ret.retn();
6640 }
6641
6642
6643 /*!
6644  * See computeCellCenterOfMass().
6645  *  \param eps a precision for the detection of degenerated arc of circles.
6646  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6647  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6648  *          components. The caller is to delete this array using decrRef() as it is
6649  *          no more needed.
6650  *  \throw If the coordinates array is not set.
6651  *  \throw If the nodal connectivity of cells is not defined.
6652  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6653  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6654  */
6655 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6656 {
6657   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6658   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6659   return ret.retn();
6660 }
6661
6662
6663 /*!
6664  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6665  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6666  *
6667  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6668  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6669  *
6670  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6671  * \throw If \a this is not fully defined (coordinates and connectivity)
6672  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6673  */
6674 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6675 {
6676   checkFullyDefined();
6677   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6678   int spaceDim=getSpaceDimension();
6679   mcIdType nbOfCells=getNumberOfCells();
6680   mcIdType nbOfNodes=getNumberOfNodes();
6681   ret->alloc(nbOfCells,spaceDim);
6682   double *ptToFill=ret->getPointer();
6683   const mcIdType *nodal=_nodal_connec->begin();
6684   const mcIdType *nodalI=_nodal_connec_index->begin();
6685   const double *coor=_coords->begin();
6686   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6687     {
6688       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6689       std::fill(ptToFill,ptToFill+spaceDim,0.);
6690       if(type!=INTERP_KERNEL::NORM_POLYHED)
6691         {
6692           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6693             {
6694               if(*conn>=0 && *conn<nbOfNodes)
6695                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6696               else
6697                 {
6698                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6699                   throw INTERP_KERNEL::Exception(oss.str());
6700                 }
6701             }
6702           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6703           if(nbOfNodesInCell>0)
6704             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6705           else
6706             {
6707               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6708               throw INTERP_KERNEL::Exception(oss.str());
6709             }
6710         }
6711       else
6712         {
6713           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6714           s.erase(-1);
6715           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6716             {
6717               if(*it>=0 && *it<nbOfNodes)
6718                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6719               else
6720                 {
6721                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6722                   throw INTERP_KERNEL::Exception(oss.str());
6723                 }
6724             }
6725           if(!s.empty())
6726             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6727           else
6728             {
6729               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6730               throw INTERP_KERNEL::Exception(oss.str());
6731             }
6732         }
6733     }
6734   return ret.retn();
6735 }
6736
6737 /*!
6738  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6739  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6740  * are specified via an array of cell ids.
6741  *  \warning Validity of the specified cell ids is not checked!
6742  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6743  *  \param [in] begin - an array of cell ids of interest.
6744  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6745  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6746  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6747  *          caller is to delete this array using decrRef() as it is no more needed.
6748  *  \throw If the coordinates array is not set.
6749  *  \throw If the nodal connectivity of cells is not defined.
6750  *
6751  *  \if ENABLE_EXAMPLES
6752  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6753  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6754  *  \endif
6755  */
6756 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6757 {
6758   DataArrayDouble *ret=DataArrayDouble::New();
6759   int spaceDim=getSpaceDimension();
6760   std::size_t nbOfTuple=std::distance(begin,end);
6761   ret->alloc(nbOfTuple,spaceDim);
6762   double *ptToFill=ret->getPointer();
6763   double *tmp=new double[spaceDim];
6764   const mcIdType *nodal=_nodal_connec->begin();
6765   const mcIdType *nodalI=_nodal_connec_index->begin();
6766   const double *coor=_coords->begin();
6767   for(const mcIdType *w=begin;w!=end;w++)
6768     {
6769       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6770       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6771       ptToFill+=spaceDim;
6772     }
6773   delete [] tmp;
6774   return ret;
6775 }
6776
6777 /*!
6778  * 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".
6779  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6780  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6781  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6782  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6783  *
6784  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6785  * \throw If spaceDim!=3 or meshDim!=2.
6786  * \throw If connectivity of \a this is invalid.
6787  * \throw If connectivity of a cell in \a this points to an invalid node.
6788  */
6789 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6790 {
6791   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6792   mcIdType nbOfCells=getNumberOfCells();
6793   mcIdType nbOfNodes(getNumberOfNodes());
6794   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6796   ret->alloc(nbOfCells,4);
6797   double *retPtr(ret->getPointer());
6798   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6799   const double *coor(_coords->begin());
6800   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6801     {
6802       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6803       if(nodalI[1]-nodalI[0]>=4)
6804         {
6805           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6806                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6807                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6808           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6809                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6810                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6811           double cc[3]={aa[1]*bb[2]-aa[2]*bb[1],aa[2]*bb[0]-aa[0]*bb[2],aa[0]*bb[1]-aa[1]*bb[0]};
6812           double aa_norm(sqrt(aa[0]*aa[0]+aa[1]*aa[1]+aa[2]*aa[2])),bb_norm(sqrt(bb[0]*bb[0]+bb[1]*bb[1]+bb[2]*bb[2]));
6813           for(int j=0;j<3;j++)
6814             {
6815               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6816               if(nodeId>=0 && nodeId<nbOfNodes)
6817                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6818               else
6819                 {
6820                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6821                   throw INTERP_KERNEL::Exception(oss.str());
6822                 }
6823             }
6824           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6825             {
6826               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6827               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6828             }
6829           else
6830             {
6831               if(nodalI[1]-nodalI[0]==4)
6832                 {
6833                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6834                   throw INTERP_KERNEL::Exception(oss.str());
6835                 }
6836               //
6837               double dd[3]={0.,0.,0.};
6838               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6839                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6840               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6841               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6842               std::copy(dd,dd+3,matrix+4*2);
6843               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6844               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6845             }
6846         }
6847       else
6848         {
6849           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6850           throw INTERP_KERNEL::Exception(oss.str());
6851         }
6852     }
6853   return ret.retn();
6854 }
6855
6856 /*!
6857  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6858  *
6859  */
6860 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6861 {
6862   if(!da)
6863     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6864   da->checkAllocated();
6865   std::string name(da->getName());
6866   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6867   if(name.empty())
6868     ret->setName("Mesh");
6869   ret->setCoords(da);
6870   mcIdType nbOfTuples(da->getNumberOfTuples());
6871   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6872   c->alloc(2*nbOfTuples,1);
6873   cI->alloc(nbOfTuples+1,1);
6874   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6875   *cip++=0;
6876   for(mcIdType i=0;i<nbOfTuples;i++)
6877     {
6878       *cp++=INTERP_KERNEL::NORM_POINT1;
6879       *cp++=i;
6880       *cip++=2*(i+1);
6881     }
6882   ret->setConnectivity(c,cI,true);
6883   return ret.retn();
6884 }
6885
6886 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6887 {
6888   if(!da)
6889     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6890   da->checkAllocated();
6891   std::string name(da->getName());
6892   MCAuto<MEDCouplingUMesh> ret;
6893   {
6894     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6895     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6896     arr->alloc(da->getNumberOfTuples());
6897     tmp->setCoordsAt(0,arr);
6898     ret=tmp->buildUnstructured();
6899   }
6900   ret->setCoords(da);
6901   if(name.empty())
6902     ret->setName("Mesh");
6903   else
6904     ret->setName(name);
6905   return ret;
6906 }
6907
6908 /*!
6909  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6910  * Cells and nodes of
6911  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6912  *  \param [in] mesh1 - the first mesh.
6913  *  \param [in] mesh2 - the second mesh.
6914  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6915  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6916  *          is no more needed.
6917  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6918  *  \throw If the coordinates array is not set in none of the meshes.
6919  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6920  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6921  */
6922 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6923 {
6924   std::vector<const MEDCouplingUMesh *> tmp(2);
6925   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6926   return MergeUMeshes(tmp);
6927 }
6928
6929 /*!
6930  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6931  * Cells and nodes of
6932  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6933  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6934  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6935  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6936  *          is no more needed.
6937  *  \throw If \a a.size() == 0.
6938  *  \throw If \a a[ *i* ] == NULL.
6939  *  \throw If the coordinates array is not set in none of the meshes.
6940  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6941  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6942  */
6943 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6944 {
6945   std::size_t sz=a.size();
6946   if(sz==0)
6947     return MergeUMeshesLL(a);
6948   for(std::size_t ii=0;ii<sz;ii++)
6949     if(!a[ii])
6950       {
6951         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6952         throw INTERP_KERNEL::Exception(oss.str());
6953       }
6954   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6955   std::vector< const MEDCouplingUMesh * > aa(sz);
6956   int spaceDim=-3;
6957   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6958     {
6959       const MEDCouplingUMesh *cur=a[i];
6960       const DataArrayDouble *coo=cur->getCoords();
6961       if(coo)
6962         spaceDim=int(coo->getNumberOfComponents());
6963     }
6964   if(spaceDim==-3)
6965     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6966   for(std::size_t i=0;i<sz;i++)
6967     {
6968       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6969       aa[i]=bb[i];
6970     }
6971   return MergeUMeshesLL(aa);
6972 }
6973
6974 /*!
6975  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6976  * dimension and sharing the node coordinates array.
6977  * All cells of the first mesh precede all cells of the second mesh
6978  * within the result mesh.
6979  *  \param [in] mesh1 - the first mesh.
6980  *  \param [in] mesh2 - the second mesh.
6981  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6982  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6983  *          is no more needed.
6984  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6985  *  \throw If the meshes do not share the node coordinates array.
6986  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6987  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6988  */
6989 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6990 {
6991   std::vector<const MEDCouplingUMesh *> tmp(2);
6992   tmp[0]=mesh1; tmp[1]=mesh2;
6993   return MergeUMeshesOnSameCoords(tmp);
6994 }
6995
6996 /*!
6997  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6998  * dimension and sharing the node coordinates array.
6999  * All cells of the *i*-th mesh precede all cells of the
7000  * (*i*+1)-th mesh within the result mesh.
7001  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7002  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7003  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7004  *          is no more needed.
7005  *  \throw If \a a.size() == 0.
7006  *  \throw If \a a[ *i* ] == NULL.
7007  *  \throw If the meshes do not share the node coordinates array.
7008  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7009  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7010  */
7011 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7012 {
7013   if(meshes.empty())
7014     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7015   for(std::size_t ii=0;ii<meshes.size();ii++)
7016     if(!meshes[ii])
7017       {
7018         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7019         throw INTERP_KERNEL::Exception(oss.str());
7020       }
7021   const DataArrayDouble *coords=meshes.front()->getCoords();
7022   int meshDim=meshes.front()->getMeshDimension();
7023   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7024   mcIdType meshLgth=0;
7025   mcIdType meshIndexLgth=0;
7026   for(;iter!=meshes.end();iter++)
7027     {
7028       if(coords!=(*iter)->getCoords())
7029         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7030       if(meshDim!=(*iter)->getMeshDimension())
7031         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7032       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7033       meshIndexLgth+=(*iter)->getNumberOfCells();
7034     }
7035   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7036   nodal->alloc(meshLgth,1);
7037   mcIdType *nodalPtr=nodal->getPointer();
7038   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7039   nodalIndex->alloc(meshIndexLgth+1,1);
7040   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7041   mcIdType offset=0;
7042   for(iter=meshes.begin();iter!=meshes.end();iter++)
7043     {
7044       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7045       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7046       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7047       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7048       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7049       if(iter!=meshes.begin())
7050         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7051       else
7052         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7053       offset+=meshLgth2;
7054     }
7055   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7056   ret->setName("merge");
7057   ret->setMeshDimension(meshDim);
7058   ret->setConnectivity(nodal,nodalIndex,true);
7059   ret->setCoords(coords);
7060   return ret;
7061 }
7062
7063 /*!
7064  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7065  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7066  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7067  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7068  * New" mode are returned for each input mesh.
7069  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7070  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7071  *          valid values [0,1,2], see zipConnectivityTraducer().
7072  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7073  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7074  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7075  *          no more needed.
7076  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7077  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7078  *          is no more needed.
7079  *  \throw If \a meshes.size() == 0.
7080  *  \throw If \a meshes[ *i* ] == NULL.
7081  *  \throw If the meshes do not share the node coordinates array.
7082  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7083  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7084  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7085  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7086  */
7087 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7088 {
7089   //All checks are delegated to MergeUMeshesOnSameCoords
7090   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7091   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7092   corr.resize(meshes.size());
7093   std::size_t nbOfMeshes=meshes.size();
7094   mcIdType offset=0;
7095   const mcIdType *o2nPtr=o2n->begin();
7096   for(std::size_t i=0;i<nbOfMeshes;i++)
7097     {
7098       DataArrayIdType *tmp=DataArrayIdType::New();
7099       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7100       tmp->alloc(curNbOfCells,1);
7101       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7102       offset+=curNbOfCells;
7103       tmp->setName(meshes[i]->getName());
7104       corr[i]=tmp;
7105     }
7106   return ret.retn();
7107 }
7108
7109 /*!
7110  * Makes all given meshes share the nodal connectivity array. The common connectivity
7111  * array is created by concatenating the connectivity arrays of all given meshes. All
7112  * the given meshes must be of the same space dimension but dimension of cells **can
7113  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7114  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7115  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7116  *  \param [in,out] meshes - a vector of meshes to update.
7117  *  \throw If any of \a meshes is NULL.
7118  *  \throw If the coordinates array is not set in any of \a meshes.
7119  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7120  *  \throw If \a meshes are of different space dimension.
7121  */
7122 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7123 {
7124   std::size_t sz=meshes.size();
7125   if(sz==0 || sz==1)
7126     return;
7127   std::vector< const DataArrayDouble * > coords(meshes.size());
7128   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7129   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7130     {
7131       if((*it))
7132         {
7133           (*it)->checkConnectivityFullyDefined();
7134           const DataArrayDouble *coo=(*it)->getCoords();
7135           if(coo)
7136             *it2=coo;
7137           else
7138             {
7139               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7140               oss << " has no coordinate array defined !";
7141               throw INTERP_KERNEL::Exception(oss.str());
7142             }
7143         }
7144       else
7145         {
7146           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7147           oss << " is null !";
7148           throw INTERP_KERNEL::Exception(oss.str());
7149         }
7150     }
7151   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7152   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7153   mcIdType offset=(*it)->getNumberOfNodes();
7154   (*it++)->setCoords(res);
7155   for(;it!=meshes.end();it++)
7156     {
7157       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7158       (*it)->setCoords(res);
7159       (*it)->shiftNodeNumbersInConn(offset);
7160       offset+=oldNumberOfNodes;
7161     }
7162 }
7163
7164 /*!
7165  * Merges nodes coincident with a given precision within all given meshes that share
7166  * the nodal connectivity array. The given meshes **can be of different** mesh
7167  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7168  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7169  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7170  *  \param [in,out] meshes - a vector of meshes to update.
7171  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7172  *  \throw If any of \a meshes is NULL.
7173  *  \throw If the \a meshes do not share the same node coordinates array.
7174  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7175  */
7176 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7177 {
7178   if(meshes.empty())
7179     return ;
7180   std::set<const DataArrayDouble *> s;
7181   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7182     {
7183       if(*it)
7184         s.insert((*it)->getCoords());
7185       else
7186         {
7187           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 !";
7188           throw INTERP_KERNEL::Exception(oss.str());
7189         }
7190     }
7191   if(s.size()!=1)
7192     {
7193       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 !";
7194       throw INTERP_KERNEL::Exception(oss.str());
7195     }
7196   const DataArrayDouble *coo=*(s.begin());
7197   if(!coo)
7198     return;
7199   //
7200   DataArrayIdType *comm,*commI;
7201   coo->findCommonTuples(eps,-1,comm,commI);
7202   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7203   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7204   mcIdType newNbOfNodes;
7205   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7206   if(oldNbOfNodes==newNbOfNodes)
7207     return ;
7208   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7209   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7210     {
7211       (*it)->renumberNodesInConn(o2n->begin());
7212       (*it)->setCoords(newCoords);
7213     }
7214 }
7215
7216
7217 /*!
7218  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7219  */
7220 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7221 {
7222   std::size_t i, ip1;
7223   double v[3]={0.,0.,0.};
7224   std::size_t sz=std::distance(begin,end);
7225   if(!isQuadratic)
7226     for(i=0;i<sz;i++)
7227       {
7228         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7229         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7230         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];
7231         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7232         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7233       }
7234   else
7235     {
7236       // Same algorithm as above but also using intermediate quadratic points.
7237       // (taking only linear points might lead to issues if the linearized version of the
7238       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7239       std::size_t hsz = sz/2;
7240       for(std::size_t j=0;j<sz;j++)
7241         {
7242           if (j%2)  // current point i is quadratic, next point i+1 is standard
7243             {
7244               i = hsz+(j-1)/2;
7245               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7246             }
7247           else      // current point i is standard, next point i+1 is quadratic
7248             {
7249               i = j/2;
7250               ip1 = j/2+hsz;
7251             }
7252           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7253           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7254           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7255         }
7256     }
7257   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7258   return (ret>0.);
7259 }
7260
7261 /*!
7262  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7263  */
7264 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7265 {
7266   std::vector<std::pair<mcIdType,mcIdType> > edges;
7267   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7268   const mcIdType *bgFace=begin;
7269   for(std::size_t i=0;i<nbOfFaces;i++)
7270     {
7271       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7272       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7273       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7274         {
7275           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7276           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7277             return false;
7278           edges.push_back(p1);
7279         }
7280       bgFace=endFace+1;
7281     }
7282   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7283 }
7284
7285 /*!
7286  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7287  */
7288 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7289 {
7290   double vec0[3],vec1[3];
7291   std::size_t sz=std::distance(begin,end);
7292   if(sz%2!=0)
7293     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7294   mcIdType nbOfNodes=ToIdType(sz/2);
7295   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7296   const double *pt0=coords+3*begin[0];
7297   const double *pt1=coords+3*begin[nbOfNodes];
7298   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7299   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7300 }
7301
7302 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7303 {
7304   std::size_t sz=std::distance(begin,end);
7305   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7306   std::size_t nbOfNodes(sz/2);
7307   std::copy(begin,end,(mcIdType *)tmp);
7308   for(std::size_t j=1;j<nbOfNodes;j++)
7309     {
7310       begin[j]=tmp[nbOfNodes-j];
7311       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7312     }
7313 }
7314
7315 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7316 {
7317   std::size_t sz=std::distance(begin,end);
7318   if(sz!=4)
7319     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7320   double vec0[3],vec1[3];
7321   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7322   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];
7323   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;
7324 }
7325
7326 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7327 {
7328   std::size_t sz=std::distance(begin,end);
7329   if(sz!=5)
7330     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7331   double vec0[3];
7332   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7333   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7334   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7335 }
7336
7337 /*!
7338  * 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 )
7339  * 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
7340  * a 2D space.
7341  *
7342  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7343  * \param [in] coords the coordinates with nb of components exactly equal to 3
7344  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7345  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7346  */
7347 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7348                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7349 {
7350   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7351   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7352   double *vPtr=v->getPointer();
7353   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7354   double *pPtr=p->getPointer();
7355   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7356   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7357   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7358     {
7359       mcIdType face = e_f[e_fi[index] + i];
7360       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7361       // to differentiate faces going to different cells:
7362       pPtr++, *pPtr = 0;
7363       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7364         *pPtr += FromIdType<double>(f_e[j]);
7365     }
7366   pPtr=p->getPointer(); vPtr=v->getPointer();
7367   DataArrayIdType *comm1=0,*commI1=0;
7368   v->findCommonTuples(eps,-1,comm1,commI1);
7369   for (mcIdType i = 0; i < nbFaces; i++)
7370     if (comm1->findIdFirstEqual(i) < 0)
7371       {
7372         comm1->pushBackSilent(i);
7373         commI1->pushBackSilent(comm1->getNumberOfTuples());
7374       }
7375   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7376   const mcIdType *comm1Ptr=comm1->begin();
7377   const mcIdType *commI1Ptr=commI1->begin();
7378   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7379   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7380   //
7381   for(mcIdType i=0;i<nbOfGrps1;i++)
7382     {
7383       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7384       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7385       DataArrayIdType *comm2=0,*commI2=0;
7386       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7387       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7388         if (comm2->findIdFirstEqual(j) < 0)
7389           {
7390             comm2->pushBackSilent(j);
7391             commI2->pushBackSilent(comm2->getNumberOfTuples());
7392           }
7393       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7394       const mcIdType *comm2Ptr=comm2->begin();
7395       const mcIdType *commI2Ptr=commI2->begin();
7396       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7397       for(mcIdType j=0;j<nbOfGrps2;j++)
7398         {
7399           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7400             {
7401               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7402               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7403               res->pushBackSilent(-1);
7404             }
7405           else
7406             {
7407               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7408               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7409               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7410               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7411               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7412               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7413               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7414               const mcIdType *idsNodePtr=idsNode->begin();
7415               double center[3]; center[0]=pPtr[2*pointId]*vPtr[3*vecId]; center[1]=pPtr[2*pointId]*vPtr[3*vecId+1]; center[2]=pPtr[2*pointId]*vPtr[3*vecId+2];
7416               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7417               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7418               if(std::abs(norm)>eps)
7419                 {
7420                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7421                   mm3->rotate(center,vec,angle);
7422                 }
7423               mm3->changeSpaceDimension(2);
7424               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7425               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7426               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7427               mcIdType nbOfCells=mm4->getNumberOfCells();
7428               for(mcIdType k=0;k<nbOfCells;k++)
7429                 {
7430                   int l=0;
7431                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7432                     res->pushBackSilent(idsNodePtr[*work]);
7433                   res->pushBackSilent(-1);
7434                 }
7435             }
7436         }
7437     }
7438   res->popBackSilent();
7439 }
7440
7441 /*!
7442  * 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
7443  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7444  *
7445  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7446  * \param [in] coords coordinates expected to have 3 components.
7447  * \param [in] begin start of the nodal connectivity of the face.
7448  * \param [in] end end of the nodal connectivity (excluded) of the face.
7449  * \param [out] v the normalized vector of size 3
7450  * \param [out] p the pos of plane
7451  */
7452 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7453 {
7454   std::size_t nbPoints=std::distance(begin,end);
7455   if(nbPoints<3)
7456     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7457   double vec[3]={0.,0.,0.};
7458   std::size_t j=0;
7459   bool refFound=false;
7460   for(;j<nbPoints-1 && !refFound;j++)
7461     {
7462       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7463       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7464       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7465       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7466       if(norm>eps)
7467         {
7468           refFound=true;
7469           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7470         }
7471     }
7472   for(std::size_t i=j;i<nbPoints-1;i++)
7473     {
7474       double curVec[3];
7475       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7476       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7477       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7478       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7479       if(norm<eps)
7480         continue;
7481       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7482       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];
7483       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7484       if(norm>eps)
7485         {
7486           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7487           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7488           return ;
7489         }
7490     }
7491   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7492 }
7493
7494 /*!
7495  * This method tries to obtain a well oriented polyhedron.
7496  * If the algorithm fails, an exception will be thrown.
7497  */
7498 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7499 {
7500   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7501   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7502   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7503   isPerm[0]=true;
7504   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7505   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7506   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7507   //
7508   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7509     {
7510       bgFace=begin;
7511       std::size_t smthChanged=0;
7512       for(std::size_t i=0;i<nbOfFaces;i++)
7513         {
7514           endFace=std::find(bgFace+1,end,-1);
7515           nbOfEdgesInFace=std::distance(bgFace,endFace);
7516           if(!isPerm[i])
7517             {
7518               bool b=false;
7519               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7520                 {
7521                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7522                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7523                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7524                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7525                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7526                 }
7527               if(isPerm[i])
7528                 {
7529                   if(!b)
7530                     std::reverse(bgFace+1,endFace);
7531                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7532                     {
7533                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7534                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7535                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7536                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7537                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7538                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7539                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7540                       if(it!=edgesOK.end())
7541                         {
7542                           edgesOK.erase(it);
7543                           edgesFinished.push_back(p1);
7544                         }
7545                       else
7546                         edgesOK.push_back(p1);
7547                     }
7548                 }
7549             }
7550           bgFace=endFace+1;
7551         }
7552       if(smthChanged==0)
7553         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7554     }
7555   if(!edgesOK.empty())
7556     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7557   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7558     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7559       bgFace=begin;
7560       for(std::size_t i=0;i<nbOfFaces;i++)
7561         {
7562           endFace=std::find(bgFace+1,end,-1);
7563           std::reverse(bgFace+1,endFace);
7564           bgFace=endFace+1;
7565         }
7566     }
7567 }
7568
7569
7570 /*!
7571  * This method makes the assumption spacedimension == meshdimension == 2.
7572  * This method works only for linear cells.
7573  *
7574  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7575  */
7576 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7577 {
7578   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7579     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7580   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7581   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7582   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7583   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7584   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7585   mcIdType nbCells=skin->getNumberOfCells();
7586   if(nbCells==nbOfNodesExpected)
7587     return buildUnionOf2DMeshLinear(skin,n2o);
7588   else if(2*nbCells==nbOfNodesExpected)
7589     return buildUnionOf2DMeshQuadratic(skin,n2o);
7590   else
7591     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7592 }
7593
7594 /*!
7595  * This method makes the assumption spacedimension == meshdimension == 3.
7596  * This method works only for linear cells.
7597  *
7598  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7599  */
7600 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7601 {
7602   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7603     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7604   MCAuto<MEDCouplingUMesh> m=computeSkin();
7605   const mcIdType *conn=m->getNodalConnectivity()->begin();
7606   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7607   mcIdType nbOfCells=m->getNumberOfCells();
7608   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7609   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7610   if(nbOfCells<1)
7611     return ret.retn();
7612   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7613   for(mcIdType i=1;i<nbOfCells;i++)
7614     {
7615       *work++=-1;
7616       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7617     }
7618   return ret.retn();
7619 }
7620
7621 /*!
7622  * \brief Creates a graph of cell neighbors
7623  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7624  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7625  *  For example
7626  *  - index:  0 3 5 6 6
7627  *  - value:  1 2 3 2 3 3
7628  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7629  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7630  */
7631 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7632 {
7633   checkConnectivityFullyDefined();
7634
7635   int meshDim = this->getMeshDimension();
7636   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7637   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7638   this->getReverseNodalConnectivity(revConn,indexr);
7639   const mcIdType* indexr_ptr=indexr->begin();
7640   const mcIdType* revConn_ptr=revConn->begin();
7641
7642   const MEDCoupling::DataArrayIdType* index;
7643   const MEDCoupling::DataArrayIdType* conn;
7644   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7645   index=this->getNodalConnectivityIndex();
7646   mcIdType nbCells=this->getNumberOfCells();
7647   const mcIdType* index_ptr=index->begin();
7648   const mcIdType* conn_ptr=conn->begin();
7649
7650   //creating graph arcs (cell to cell relations)
7651   //arcs are stored in terms of (index,value) notation
7652   // 0 3 5 6 6
7653   // 1 2 3 2 3 3
7654   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7655   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7656
7657   //warning here one node have less than or equal effective number of cell with it
7658   //but cell could have more than effective nodes
7659   //because other equals nodes in other domain (with other global inode)
7660   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7661   std::vector <mcIdType> cell2cell;
7662   cell2cell.reserve(3*nbCells);
7663
7664   for (mcIdType icell=0; icell<nbCells;icell++)
7665     {
7666       std::map<mcIdType,mcIdType > counter;
7667       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7668         {
7669           mcIdType inode=conn_ptr[iconn];
7670           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7671             {
7672               mcIdType icell2=revConn_ptr[iconnr];
7673               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7674               if (iter!=counter.end()) (iter->second)++;
7675               else counter.insert(std::make_pair(icell2,1));
7676             }
7677         }
7678       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7679            iter!=counter.end(); iter++)
7680         if (iter->second >= meshDim)
7681           {
7682             cell2cell_index[icell+1]++;
7683             cell2cell.push_back(iter->first);
7684           }
7685     }
7686   indexr->decrRef();
7687   revConn->decrRef();
7688   cell2cell_index[0]=0;
7689   for (mcIdType icell=0; icell<nbCells;icell++)
7690     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7691
7692   //filling up index and value to create skylinearray structure
7693   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7694   return array;
7695 }
7696
7697
7698 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7699 {
7700   mcIdType nbOfCells=getNumberOfCells();
7701   if(nbOfCells<=0)
7702     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7703   ofs << "  <" << getVTKDataSetType() << ">\n";
7704   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7705   ofs << "      <PointData>\n" << pointData << std::endl;
7706   ofs << "      </PointData>\n";
7707   ofs << "      <CellData>\n" << cellData << std::endl;
7708   ofs << "      </CellData>\n";
7709   ofs << "      <Points>\n";
7710   if(getSpaceDimension()==3)
7711     _coords->writeVTK(ofs,8,"Points",byteData);
7712   else
7713     {
7714       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7715       coo->writeVTK(ofs,8,"Points",byteData);
7716     }
7717   ofs << "      </Points>\n";
7718   ofs << "      <Cells>\n";
7719   const mcIdType *cPtr=_nodal_connec->begin();
7720   const mcIdType *cIPtr=_nodal_connec_index->begin();
7721   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7722   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7723   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7724   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7725   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7726   mcIdType szFaceOffsets=0,szConn=0;
7727   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7728     {
7729       *w2=cPtr[cIPtr[i]];
7730       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7731         {
7732           *w1=-1;
7733           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7734           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7735         }
7736       else
7737         {
7738           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7739           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7740           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7741           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7742           w4=std::copy(c.begin(),c.end(),w4);
7743         }
7744     }
7745   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7746   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7747     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7748   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7749   types->writeVTK(ofs,8,"UInt8","types",byteData);
7750   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7751   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7752   if(szFaceOffsets!=0)
7753     {//presence of Polyhedra
7754       connectivity->reAlloc(szConn);
7755       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7756       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7757       w1=faces->getPointer();
7758       for(mcIdType i=0;i<nbOfCells;i++)
7759         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7760           {
7761             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7762             *w1++=nbFaces;
7763             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7764             for(mcIdType j=0;j<nbFaces;j++)
7765               {
7766                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7767                 *w1++=ToIdType(std::distance(w6,w5));
7768                 w1=std::copy(w6,w5,w1);
7769                 w6=w5+1;
7770               }
7771           }
7772       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7773     }
7774   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7775   ofs << "      </Cells>\n";
7776   ofs << "    </Piece>\n";
7777   ofs << "  </" << getVTKDataSetType() << ">\n";
7778 }
7779
7780 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7781 {
7782   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7783   if(_mesh_dim==-2)
7784     { stream << " Not set !"; return ; }
7785   stream << " Mesh dimension : " << _mesh_dim << ".";
7786   if(_mesh_dim==-1)
7787     return ;
7788   if(!_coords)
7789     { stream << " No coordinates set !"; return ; }
7790   if(!_coords->isAllocated())
7791     { stream << " Coordinates set but not allocated !"; return ; }
7792   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7793   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7794   if(!_nodal_connec_index)
7795     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7796   if(!_nodal_connec_index->isAllocated())
7797     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7798   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7799   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7800   if(cpt!=1 || lgth<1)
7801     return ;
7802   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7803 }
7804
7805 std::string MEDCouplingUMesh::getVTKDataSetType() const
7806 {
7807   return std::string("UnstructuredGrid");
7808 }
7809
7810 std::string MEDCouplingUMesh::getVTKFileExtension() const
7811 {
7812   return std::string("vtu");
7813 }
7814
7815
7816
7817 /**
7818  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7819  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7820  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7821  * The caller is to deal with the resulting DataArrayIdType.
7822  *  \throw If the coordinate array is not set.
7823  *  \throw If the nodal connectivity of the cells is not defined.
7824  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7825  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7826  *
7827  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7828  */
7829 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7830 {
7831   checkFullyDefined();
7832   if(getMeshDimension()!=1)
7833     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7834
7835   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7836   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7837   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7838   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7839   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7840   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7841   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7842   const mcIdType * dsi(_dsi->begin());
7843   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7844   m_points=0;
7845   if (dsii->getNumberOfTuples())
7846     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7847
7848   mcIdType nc=getNumberOfCells();
7849   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7850   result->alloc(nc,1);
7851
7852   // set of edges not used so far
7853   std::set<mcIdType> edgeSet;
7854   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7855
7856   mcIdType startSeg=0;
7857   mcIdType newIdx=0;
7858   // while we have points with only one neighbor segments
7859   do
7860     {
7861       std::list<mcIdType> linePiece;
7862       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7863       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7864         {
7865           // Fill the list forward (resp. backward) from the start segment:
7866           mcIdType activeSeg = startSeg;
7867           mcIdType prevPointId = -20;
7868           mcIdType ptId;
7869           while (!edgeSet.empty())
7870             {
7871               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7872                 {
7873                   if (direction==0)
7874                     linePiece.push_back(activeSeg);
7875                   else
7876                     linePiece.push_front(activeSeg);
7877                   edgeSet.erase(activeSeg);
7878                 }
7879
7880               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7881               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7882               if (dsi[ptId] == 1) // hitting the end of the line
7883                 break;
7884
7885               prevPointId = ptId;
7886               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7887               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7888
7889               //for piecewise meshes made up of closed parts
7890               bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7891               if(segmentAlreadyTreated)
7892                 break;
7893             }
7894         }
7895       // Done, save final piece into DA:
7896       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7897       newIdx += ToIdType(linePiece.size());
7898
7899       // identify next valid start segment (one which is not consumed)
7900       if(!edgeSet.empty())
7901         startSeg = *(edgeSet.begin());
7902
7903     }
7904   while (!edgeSet.empty());
7905   return result.retn();
7906 }
7907
7908 /**
7909  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7910  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7911  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7912  * a minimal creation of new nodes is wanted.
7913  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7914  * nodes if a SEG3 is split without information of middle.
7915  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7916  * avoid to have a non conform mesh.
7917  *
7918  * \return mcIdType - the number of new nodes created (in most of cases 0).
7919  *
7920  * \throw If \a this is not coherent.
7921  * \throw If \a this has not spaceDim equal to 2.
7922  * \throw If \a this has not meshDim equal to 2.
7923  * \throw If some subcells needed to be split are orphan.
7924  * \sa MEDCouplingUMesh::conformize2D
7925  */
7926 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7927 {
7928   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7929     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7930   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7931   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7932     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7933   if(midOpt==0 && midOptI==0)
7934     {
7935       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7936       return 0;
7937     }
7938   else if(midOpt!=0 && midOptI!=0)
7939     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7940   else
7941     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7942 }
7943
7944 /*!
7945  * 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
7946  * 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
7947  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7948  * 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
7949  * 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.
7950  *
7951  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7952  */
7953 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7954 {
7955   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7956   if(sz>=4)
7957     {
7958       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7959       if(cm.getDimension()==2)
7960         {
7961           const mcIdType *node=nodalConnBg+1;
7962           mcIdType startNode=*node++;
7963           double refX=coords[2*startNode];
7964           for(;node!=nodalConnEnd;node++)
7965             {
7966               if(coords[2*(*node)]<refX)
7967                 {
7968                   startNode=*node;
7969                   refX=coords[2*startNode];
7970                 }
7971             }
7972           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7973           refX=1e300;
7974           double tmp1;
7975           double tmp2[2];
7976           double angle0=-M_PI/2;
7977           //
7978           mcIdType nextNode=-1;
7979           mcIdType prevNode=-1;
7980           double resRef;
7981           double angleNext=0.;
7982           while(nextNode!=startNode)
7983             {
7984               nextNode=-1;
7985               resRef=1e300;
7986               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7987                 {
7988                   if(*node!=tmpOut.back() && *node!=prevNode)
7989                     {
7990                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7991                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7992                       double res;
7993                       if(angleM<=angle0)
7994                         res=angle0-angleM;
7995                       else
7996                         res=angle0-angleM+2.*M_PI;
7997                       if(res<resRef)
7998                         {
7999                           nextNode=*node;
8000                           resRef=res;
8001                           angleNext=angleM;
8002                         }
8003                     }
8004                 }
8005               if(nextNode!=startNode)
8006                 {
8007                   angle0=angleNext-M_PI;
8008                   if(angle0<-M_PI)
8009                     angle0+=2*M_PI;
8010                   prevNode=tmpOut.back();
8011                   tmpOut.push_back(nextNode);
8012                 }
8013             }
8014           std::vector<mcIdType> tmp3(2*(sz-1));
8015           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8016           std::copy(nodalConnBg+1,nodalConnEnd,it);
8017           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8018             {
8019               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8020               return false;
8021             }
8022           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8023             {
8024               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8025               return false;
8026             }
8027           else
8028             {
8029               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8030               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8031               return true;
8032             }
8033         }
8034       else
8035         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8036     }
8037   else
8038     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8039 }
8040
8041 /*!
8042  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8043  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8044  * This method start from id 0 that will be contained in output DataArrayIdType. It searches then all neighbors of id0 looking at arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
8045  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8046  * A negative value in \b arrIn means that it is ignored.
8047  * 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.
8048  *
8049  * \param [in] arrIn arr origin array from which the extraction will be done.
8050  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8051  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8052  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8053  */
8054 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8055 {
8056   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8057   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8058 }
8059
8060 /*!
8061  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8062  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8063  * This method start from id 0 that will be contained in output DataArrayIdType. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
8064  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8065  * A negative value in \b arrIn means that it is ignored.
8066  * 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.
8067  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8068  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8069  * \param [in] arrIn arr origin array from which the extraction will be done.
8070  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8071  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8072  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8073  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8074  * \sa MEDCouplingUMesh::partitionBySpreadZone
8075  */
8076 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8077 {
8078   nbOfDepthPeelingPerformed=0;
8079   if(!arrIndxIn)
8080     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8081   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8082   if(nbOfTuples<=0)
8083     {
8084       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8085       return ret;
8086     }
8087   //
8088   std::vector<bool> fetched(nbOfTuples,false);
8089   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8090 }
8091
8092
8093
8094 /*!
8095  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8096  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8097  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8098  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8099  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8100  *
8101  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8102  */
8103 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8104 {
8105   checkFullyDefined();
8106   int mdim=getMeshDimension();
8107   int spaceDim=getSpaceDimension();
8108   if(mdim!=spaceDim)
8109     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8110   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8111   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8112   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8113   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8114   ret->setCoords(getCoords());
8115   ret->allocateCells(ToIdType(partition.size()));
8116   //
8117   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8118     {
8119       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8120       MCAuto<DataArrayIdType> cell;
8121       switch(mdim)
8122       {
8123         case 2:
8124           cell=tmp->buildUnionOf2DMesh();
8125           break;
8126         case 3:
8127           cell=tmp->buildUnionOf3DMesh();
8128           break;
8129         default:
8130           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8131       }
8132
8133       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8134     }
8135   //
8136   ret->finishInsertingCells();
8137   return ret.retn();
8138 }
8139
8140 /*!
8141  * This method partitions \b this into contiguous zone.
8142  * This method only needs a well defined connectivity. Coordinates are not considered here.
8143  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8144  */
8145 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8146 {
8147   DataArrayIdType *neigh=0,*neighI=0;
8148   computeNeighborsOfCells(neigh,neighI);
8149   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8150   return PartitionBySpreadZone(neighAuto,neighIAuto);
8151 }
8152
8153 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8154 {
8155   if(!arrIn || !arrIndxIn)
8156     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8157   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8158   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8159   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8160     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8161   mcIdType nbOfCellsCur(nbOfTuples-1);
8162   std::vector<DataArrayIdType *> ret;
8163   if(nbOfCellsCur<=0)
8164     return ret;
8165   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8166   std::vector< MCAuto<DataArrayIdType> > ret2;
8167   mcIdType seed=0;
8168   while(seed<nbOfCellsCur)
8169     {
8170       mcIdType nbOfPeelPerformed=0;
8171       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8172       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8173     }
8174   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8175     ret.push_back((*it).retn());
8176   return ret;
8177 }
8178
8179 /*!
8180  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8181  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8182  *
8183  * \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.
8184  * \return a newly allocated DataArrayIdType to be managed by the caller.
8185  * \throw In case of \a code has not the right format (typically of size 3*n)
8186  */
8187 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8188 {
8189   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8190   std::size_t nb=code.size()/3;
8191   if(code.size()%3!=0)
8192     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8193   ret->alloc(nb,2);
8194   mcIdType *retPtr=ret->getPointer();
8195   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8196     {
8197       retPtr[0]=code[3*i+2];
8198       retPtr[1]=code[3*i+2]+code[3*i+1];
8199     }
8200   return ret.retn();
8201 }
8202
8203 /*!
8204  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8205  * All cells in \a this are expected to be linear 3D cells.
8206  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8207  * It leads to an increase to number of cells.
8208  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8209  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8210  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8211  *
8212  * \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.
8213  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8214  * \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.
8215  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8216  *          an id of old cell producing it. The caller is to delete this array using
8217  *         decrRef() as it is no more needed.
8218  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8219  *
8220  * \warning This method operates on each cells in this independently ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
8221  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8222  *
8223  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8224  * \throw If \a this is not fully constituted with linear 3D cells.
8225  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8226  */
8227 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8228 {
8229   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8230   checkConnectivityFullyDefined();
8231   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8232     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8233   mcIdType nbOfCells=getNumberOfCells();
8234   mcIdType nbNodes(getNumberOfNodes());
8235   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8236   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8237   mcIdType *retPt(ret->getPointer());
8238   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8239   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8240   const mcIdType *oldc(_nodal_connec->begin());
8241   const mcIdType *oldci(_nodal_connec_index->begin());
8242   const double *coords(_coords->begin());
8243   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8244     {
8245       std::vector<mcIdType> a; std::vector<double> b;
8246       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8247       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8248       const mcIdType *aa(&a[0]);
8249       if(!b.empty())
8250         {
8251           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8252             if(*it<0)
8253               *it=(-(*(it))-1+nbNodes);
8254           addPts->insertAtTheEnd(b.begin(),b.end());
8255           nbNodes+=ToIdType(b.size()/3);
8256         }
8257       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8258         newConn->insertAtTheEnd(aa,aa+4);
8259     }
8260   if(!addPts->empty())
8261     {
8262       addPts->rearrange(3);
8263       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8264       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8265       ret0->setCoords(addPts);
8266     }
8267   else
8268     {
8269       nbOfAdditionalPoints=0;
8270       ret0->setCoords(getCoords());
8271     }
8272   ret0->setNodalConnectivity(newConn);
8273   //
8274   ret->computeOffsetsFull();
8275   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8276   return ret0.retn();
8277 }
8278
8279 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8280     _own_cell(true),_cell_id(-1),_nb_cell(0)
8281 {
8282   if(mesh)
8283     {
8284       mesh->incrRef();
8285       _nb_cell=mesh->getNumberOfCells();
8286     }
8287 }
8288
8289 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8290 {
8291   if(_mesh)
8292     _mesh->decrRef();
8293   if(_own_cell)
8294     delete _cell;
8295 }
8296
8297 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8298     _own_cell(false),_cell_id(bg-1),
8299     _nb_cell(end)
8300 {
8301   if(mesh)
8302     mesh->incrRef();
8303 }
8304
8305 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8306 {
8307   _cell_id++;
8308   if(_cell_id<_nb_cell)
8309     {
8310       _cell->next();
8311       return _cell;
8312     }
8313   else
8314     return 0;
8315 }
8316
8317 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8318 {
8319   if(_mesh)
8320     _mesh->incrRef();
8321 }
8322
8323 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8324 {
8325   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8326 }
8327
8328 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8329 {
8330   if(_mesh)
8331     _mesh->decrRef();
8332 }
8333
8334 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8335     _itc(itc),
8336     _bg(bg),_end(end)
8337 {
8338   if(_mesh)
8339     _mesh->incrRef();
8340 }
8341
8342 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8343 {
8344   if(_mesh)
8345     _mesh->decrRef();
8346 }
8347
8348 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8349 {
8350   return _type;
8351 }
8352
8353 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8354 {
8355   return _end-_bg;
8356 }
8357
8358 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8359 {
8360   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8361 }
8362
8363 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8364 {
8365   if(mesh)
8366     {
8367       mesh->incrRef();
8368       _nb_cell=mesh->getNumberOfCells();
8369     }
8370 }
8371
8372 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8373 {
8374   if(_mesh)
8375     _mesh->decrRef();
8376   delete _cell;
8377 }
8378
8379 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8380 {
8381   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8382   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8383   if(_cell_id<_nb_cell)
8384     {
8385       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8386       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8387       mcIdType startId=_cell_id;
8388       _cell_id+=nbOfElems;
8389       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8390     }
8391   else
8392     return 0;
8393 }
8394
8395 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8396 {
8397   if(mesh)
8398     {
8399       _conn=mesh->getNodalConnectivity()->getPointer();
8400       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8401     }
8402 }
8403
8404 void MEDCouplingUMeshCell::next()
8405 {
8406   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8407     {
8408       _conn+=_conn_lgth;
8409       _conn_indx++;
8410     }
8411   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8412 }
8413
8414 std::string MEDCouplingUMeshCell::repr() const
8415 {
8416   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8417     {
8418       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8419       oss << " : ";
8420       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8421       return oss.str();
8422     }
8423   else
8424     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8425 }
8426
8427 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8428 {
8429   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8430     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8431   else
8432     return INTERP_KERNEL::NORM_ERROR;
8433 }
8434
8435 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8436 {
8437   lgth=_conn_lgth;
8438   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8439     return _conn;
8440   else
8441     return 0;
8442 }
8443
8444 /// @cond INTERNAL
8445
8446 namespace MEDCouplingImpl
8447 {
8448   const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8449
8450   //================================================================================
8451   /*!
8452    * \brief Encode a cell id and a mesh index into a code
8453    *  \param [in] id - cell id
8454    *  \param [in] iMesh - mesh index [0,1]
8455    *  \return mcIdType - code
8456    */
8457   //================================================================================
8458
8459   mcIdType encodeID( mcIdType id, int iMesh )
8460   {
8461     return ( id + 1 ) * ( iMesh ? -1 : 1 );
8462   }
8463   //================================================================================
8464   /*!
8465    * \brief Return cell id and mesh index by a given id
8466    *  \param [in] id - code of a cell in a mesh
8467    *  \param [out] iMesh - returned mesh index
8468    *  \return mcIdType - cell id
8469    */
8470   //================================================================================
8471
8472   mcIdType decodeID( mcIdType id, int& iMesh )
8473   {
8474     iMesh = ( id < 0 );
8475     return std::abs( id ) - 1;
8476   }
8477
8478   //================================================================================
8479   /*!
8480    * \brief return another face sharing two given nodes of a face edge
8481    *  \param [in] n0 - 1st node of the edge
8482    *  \param [in] n1 - 2nd node of the edge
8483    *  \param [in] inputFaceID - face including \a n0 andf \a n2
8484    *  \param [in] mesh - object and reference meshes
8485    *  \param [in] revNodal - reverse nodal connectivity of the two meshes
8486    *  \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8487    *  \param [out] facesByEdge - return another face including \a n0 andf \a n2
8488    *  \param [out] equalFaces - return faces equal to facesByEdge
8489    */
8490   //================================================================================
8491
8492   void getFacesOfEdge( mcIdType n0,
8493                        mcIdType n1,
8494                        mcIdType inputFaceID,
8495                        MEDCouplingUMesh* mesh[],
8496                        MCAuto<DataArrayIdType> revNodal[],
8497                        MCAuto<DataArrayIdType> revNodalIndx[],
8498                        std::vector< mcIdType >& facesByEdge,
8499                        std::vector< mcIdType >& equalFaces)
8500   {
8501     // find faces sharing the both nodes of edge
8502
8503     facesByEdge.clear();
8504     size_t prevNbF; // nb faces found in 0-th mesh
8505     for ( int iM = 0; iM < 2; ++iM )
8506       {
8507         const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8508         const mcIdType * rev    = revNodal    [ iM ]->begin();
8509
8510         mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8511         mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8512
8513         prevNbF = facesByEdge.size();
8514         facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8515
8516         auto it = std::set_intersection( rev + revInd[ n0 ],
8517                                          rev + revInd[ n0 ] + nbRevFaces0,
8518                                          rev + revInd[ n1 ],
8519                                          rev + revInd[ n1 ] + nbRevFaces1,
8520                                          facesByEdge.begin() + prevNbF );
8521         facesByEdge.resize( it - facesByEdge.begin() );
8522       }
8523
8524     // facesByEdge now contains at least the 'inputFaceID'
8525     // check if there are other faces
8526
8527     size_t nbF = facesByEdge.size();
8528     if ( nbF > 1 )
8529       {
8530         if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8531           {
8532             // remove from facesByEdge equal faces in different meshes
8533             const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8534                                          mesh[1]->getNodalConnectivity()->getConstPointer() };
8535             const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8536                                          mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8537             for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8538               {
8539                 if ( facesByEdge[ i0 ] == theUndefID )
8540                   continue;
8541                 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8542                 bool   isInputFace = ( objFaceID == inputFaceID );
8543
8544                 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8545                   {
8546                     if ( facesByEdge[ i1 ] == theUndefID )
8547                       continue;
8548
8549                     mcIdType f0 = facesByEdge[ i0 ];
8550                     mcIdType f1 = facesByEdge[ i1 ];
8551                     size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8552                     size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8553                     if ( nbNodes0 != nbNodes1 )
8554                       continue;
8555
8556                     const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8557                     const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8558                     if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8559                       {
8560                         // equal faces; remove an object one
8561                         mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8562                         if ( refFaceID == inputFaceID )
8563                           isInputFace = true;
8564
8565                         if ( std::find( equalFaces.begin(),
8566                                         equalFaces.end(), objFaceID ) == equalFaces.end() )
8567                           equalFaces.push_back( objFaceID );
8568
8569                         facesByEdge[ i0 ] = theUndefID;
8570                         if ( isInputFace )
8571                           facesByEdge[ i1 ] = theUndefID;
8572                         break;
8573                       }
8574                   }
8575                 if ( isInputFace )
8576                   facesByEdge[ i0 ] = theUndefID;
8577               }
8578           }
8579       }
8580
8581     nbF = facesByEdge.size();
8582     for ( size_t i = 0; i < facesByEdge.size(); ++i )
8583       {
8584         if ( facesByEdge[ i ] != theUndefID )
8585           {
8586             facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8587             if ( facesByEdge[ i ] == inputFaceID )
8588               facesByEdge[ i ] = theUndefID;
8589           }
8590         nbF -= ( facesByEdge[ i ] == theUndefID );
8591       }
8592
8593     if ( nbF > 1 )
8594       return; // non-manifold
8595
8596     if ( nbF < 1 )
8597       {
8598         facesByEdge.clear();
8599       }
8600     else // nbF == 1, set a found face first
8601       {
8602         if ( facesByEdge[ 0 ] == theUndefID )
8603           {
8604             for ( size_t i = 1; i < facesByEdge.size(); ++i )
8605               if ( facesByEdge[ i ] != theUndefID )
8606                 {
8607                   facesByEdge[ 0 ] = facesByEdge[ i ];
8608                   break;
8609                 }
8610           }
8611         facesByEdge.resize( 1 );
8612       }
8613     return;
8614   }
8615
8616   //================================================================================
8617   /*!
8618    * \brief Remove a face from nodal reversed connectivity
8619    *  \param [in] node - a node of the face
8620    *  \param [in] face - the face
8621    *  \param [in.out] revNodal - reverse nodal connectivity
8622    *  \param [in,out] revNodalIndx - reverse nodal connectivity index
8623    */
8624   //================================================================================
8625
8626   void removeFromRevNodal( mcIdType node,
8627                            mcIdType face,
8628                            MCAuto<DataArrayIdType>& revNodal,
8629                            MCAuto<DataArrayIdType>& revNodalIndx)
8630   {
8631     mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8632     mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8633     auto it = std::find( fBeg, fEnd, face );
8634     if ( it != fEnd )
8635       {
8636         for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8637           *( it2 - 1 ) = *it2;
8638
8639         *( fEnd - 1 ) = theUndefID;
8640       }
8641   }
8642
8643   //================================================================================
8644   /*!
8645    * \brief Check order of two nodes in a given face
8646    *  \param [inout] n0 - node 1
8647    *  \param [inout] n1 - node 2
8648    *  \param [inout] iFEnc - face
8649    *  \param [inout] mesh - mesh
8650    *  \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8651    */
8652   //================================================================================
8653
8654   bool isReverseOrder( mcIdType n0,
8655                        mcIdType n1,
8656                        mcIdType iFEnc,
8657                        MEDCouplingUMesh* mesh[] )
8658   {
8659     int iMesh;
8660     mcIdType iF = decodeID( iFEnc, iMesh );
8661
8662     const mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8663     const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8664
8665     auto it0 = std::find( conn + connI[ iF ] + 1,
8666                           conn + connI[ iF + 1 ],
8667                           n0 );
8668     auto it1 = std::find( conn + connI[ iF ] + 1,
8669                           conn + connI[ iF + 1 ],
8670                           n1 );
8671     long i0 = it0 - conn;
8672     long i1 = it1 - conn;
8673
8674     bool isRev = ( std::abs( i1 - i0 ) == 1 ) ?  i1 < i0 :  i0 < i1;
8675     return isRev;
8676   }
8677
8678   //================================================================================
8679   /*!
8680    * \brief Change orientation of a face in one of given meshes
8681    *  \param [in] iFEnc - face ID also encoding a mesh index
8682    *  \param [in,out] mesh - object and reference meshes
8683    */
8684   //================================================================================
8685
8686   void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8687   {
8688     int iMesh;
8689     mcIdType face = decodeID( iFEnc, iMesh );
8690
8691     mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8692     mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8693
8694     const INTERP_KERNEL::CellModel& cm =
8695       INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8696
8697     cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8698                               (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8699     return;
8700   }
8701 }
8702
8703 /// @endcond
8704
8705 //================================================================================
8706 /*!
8707  * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8708  *  \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8709  *              If there are no cells in \a refFaces or it is nullptr, then any face
8710  *              in \a this mesh is used as a reference
8711  *  \throw If \a this mesh is not well defined.
8712  *  \throw If \a this mesh or \refFaces are not 2D.
8713  *  \throw If \a this mesh and \refFaces do not share nodes.
8714  *  \throw If \a refFaces are not equally oriented.
8715  *  \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8716  *
8717  *  \if ENABLE_EXAMPLES
8718  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8719  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8720  *  \endif
8721  */
8722 //================================================================================
8723
8724 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8725 {
8726   checkConsistencyLight();
8727   if ( getMeshDimension() != 2 )
8728     throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8729   if ( refFaces )
8730     {
8731       refFaces->checkConsistencyLight();
8732       if ( refFaces->getMeshDimension() != 2 )
8733         throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8734       if ( getCoords() != refFaces->getCoords() )
8735         throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8736       if ( refFaces->getNumberOfCells() == 0 )
8737         refFaces = nullptr;
8738     }
8739   if ( getNumberOfCells() == 0 )
8740     return;
8741
8742   enum { _OBJ, _REF };
8743   MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8744   MCAuto<MEDCouplingUMesh> meshPtr;
8745   if ( !mesh[_REF] )
8746     {
8747       meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8748       mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8749       mesh[_REF]->allocateCells(0);
8750       mesh[_REF]->finishInsertingCells();
8751     }
8752   mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8753                                  mesh[_REF]->getNumberOfCells() };
8754   std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8755   isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8756   isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8757
8758   MCAuto<DataArrayIdType> revNodal    [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8759   MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8760   mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8761   mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8762
8763   std::vector< mcIdType > faceNodes(4);
8764   std::vector< mcIdType > facesByEdge(4), equalFaces;
8765   std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8766
8767   while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8768     {
8769       if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8770         {
8771           for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8772             if ( nbFacesToCheck[iMesh] > 0 )
8773               for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8774                 if ( !isFaceQueued[iMesh][f] )
8775                   {
8776                     faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8777                     isFaceQueued[ iMesh ][ f ] = true;
8778                     iMesh = 0;
8779                     break;
8780                   }
8781           if ( faceQueue.empty() )
8782             break;
8783         }
8784
8785       mcIdType fID = faceQueue.back();
8786       faceQueue.pop_back();
8787
8788       int iMesh, iMesh2;
8789       mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8790
8791       nbFacesToCheck[iMesh]--;
8792
8793       equalFaces.clear();
8794       faceNodes.clear();
8795       mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8796       const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8797       const int nbEdges = cm.getNumberOfSons();
8798
8799       // loop on edges of the refFace
8800       mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8801       for ( int edge = 0; edge < nbEdges; ++edge )
8802         {
8803           mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8804
8805           // get faces sharing the edge
8806           MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8807                                            facesByEdge, equalFaces );
8808
8809           if ( facesByEdge.size() > 1 )
8810             THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8811
8812           if ( facesByEdge.size() == 1 )
8813             {
8814               // compare orientation of two faces
8815               //
8816               if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8817                 {
8818                   if ( facesByEdge[0] < 0 ) // in the ref mesh
8819                     throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8820
8821                   MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8822                 }
8823               mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8824               if ( !isFaceQueued[iMesh2][face2] )
8825                 {
8826                   isFaceQueued[iMesh2][face2] = true;
8827                   faceQueue.push_back( facesByEdge[0] );
8828                 }
8829             }
8830           n0 = n1;
8831         }
8832
8833       // remove face and equalFaces from revNodal in order not to treat them again
8834       equalFaces.push_back( fID );
8835       for ( mcIdType face : equalFaces )
8836         {
8837           mcIdType f            = MEDCouplingImpl::decodeID( face, iMesh2 );
8838           const mcIdType *conn  = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8839           const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8840           mcIdType nbNodes      = connI[ f + 1 ] - connI[ f ] - 1;
8841           for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8842
8843             MEDCouplingImpl::removeFromRevNodal( *n, f,  // not to treat f again
8844                                                  revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8845         }
8846
8847     } // while() until all faces checked
8848
8849   return;
8850 }