Salome HOME
Adapt for C++17
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2020  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 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.
214  *  \param [in] eps - a not used parameter.
215  *  \throw If the mesh dimension is not set.
216  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
217  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
218  *  \throw If the connectivity data array has more than one component.
219  *  \throw If the connectivity data array has a named component.
220  *  \throw If the connectivity index data array has more than one component.
221  *  \throw If the connectivity index data array has a named component.
222  *  \throw If number of nodes defining an element does not correspond to the type of element.
223  *  \throw If the nodal connectivity includes an invalid node id.
224  */
225 void MEDCouplingUMesh::checkConsistency(double eps) const
226 {
227   checkConsistencyLight();
228   if(_mesh_dim==-1)
229     return ;
230   int meshDim=getMeshDimension();
231   mcIdType nbOfNodes=getNumberOfNodes();
232   mcIdType nbOfCells=getNumberOfCells();
233   const mcIdType *ptr=_nodal_connec->getConstPointer();
234   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
235   for(mcIdType i=0;i<nbOfCells;i++)
236     {
237       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
238       if(ToIdType(cm.getDimension())!=meshDim)
239         {
240           std::ostringstream oss;
241           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
242           throw INTERP_KERNEL::Exception(oss.str());
243         }
244       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
245       if(!cm.isDynamic())
246         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
247           {
248             std::ostringstream oss;
249             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
250             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
251             throw INTERP_KERNEL::Exception(oss.str());
252           }
253       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
254         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
255           {
256             std::ostringstream oss;
257             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
258             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
259             throw INTERP_KERNEL::Exception(oss.str());
260           }
261       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
262         {
263           mcIdType nodeId=*w;
264           if(nodeId>=0)
265             {
266               if(nodeId>=nbOfNodes)
267                 {
268                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
269                   throw INTERP_KERNEL::Exception(oss.str());
270                 }
271             }
272           else if(nodeId<-1)
273             {
274               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
275               throw INTERP_KERNEL::Exception(oss.str());
276             }
277           else
278             {
279               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
280                 {
281                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
282                   throw INTERP_KERNEL::Exception(oss.str());
283                 }
284             }
285         }
286     }
287 }
288
289 /*!
290  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
291  * elements contained in the mesh. For more info on the mesh dimension see
292  * \ref MEDCouplingUMeshPage.
293  *  \param [in] meshDim - a new mesh dimension.
294  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
295  */
296 void MEDCouplingUMesh::setMeshDimension(int meshDim)
297 {
298   if(meshDim<-1 || meshDim>3)
299     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
300   _mesh_dim=meshDim;
301   declareAsNew();
302 }
303
304 /*!
305  * Allocates memory to store an estimation of the given number of cells.
306  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
307  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
308  * If a nodal connectivity previously existed before the call of this method, it will be reset.
309  *
310  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
311  *
312  *  \if ENABLE_EXAMPLES
313  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
314  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
315  *  \endif
316  */
317 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
318 {
319   if(nbOfCells<0)
320     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
321   if(_nodal_connec_index)
322     {
323       _nodal_connec_index->decrRef();
324     }
325   if(_nodal_connec)
326     {
327       _nodal_connec->decrRef();
328     }
329   _nodal_connec_index=DataArrayIdType::New();
330   _nodal_connec_index->reserve(nbOfCells+1);
331   _nodal_connec_index->pushBackSilent(0);
332   _nodal_connec=DataArrayIdType::New();
333   _nodal_connec->reserve(2*nbOfCells);
334   _types.clear();
335   declareAsNew();
336 }
337
338 /*!
339  * Appends a cell to the connectivity array. For deeper understanding what is
340  * happening see \ref MEDCouplingUMeshNodalConnectivity.
341  *  \param [in] type - type of cell to add.
342  *  \param [in] size - number of nodes constituting this cell.
343  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
344  *
345  *  \if ENABLE_EXAMPLES
346  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
347  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
348  *  \endif
349  */
350 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
351 {
352   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
353   if(_nodal_connec_index==0)
354     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
355   if(ToIdType(cm.getDimension())==_mesh_dim)
356     {
357       if(!cm.isDynamic())
358         if(size!=ToIdType(cm.getNumberOfNodes()))
359           {
360             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
361             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
362             throw INTERP_KERNEL::Exception(oss.str());
363           }
364       mcIdType idx=_nodal_connec_index->back();
365       mcIdType val=idx+size+1;
366       _nodal_connec_index->pushBackSilent(val);
367       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
368       _types.insert(type);
369     }
370   else
371     {
372       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
373       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
374       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
375       throw INTERP_KERNEL::Exception(oss.str());
376     }
377 }
378
379 /*!
380  * Compacts data arrays to release unused memory. This method is to be called after
381  * finishing cell insertion using \a this->insertNextCell().
382  *
383  *  \if ENABLE_EXAMPLES
384  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
385  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
386  *  \endif
387  */
388 void MEDCouplingUMesh::finishInsertingCells()
389 {
390   _nodal_connec->pack();
391   _nodal_connec_index->pack();
392   _nodal_connec->declareAsNew();
393   _nodal_connec_index->declareAsNew();
394   updateTime();
395 }
396
397 /*!
398  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
399  * Useful for python users.
400  */
401 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
402 {
403   return new MEDCouplingUMeshCellIterator(this);
404 }
405
406 /*!
407  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
408  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
409  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
410  * Useful for python users.
411  */
412 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
413 {
414   if(!checkConsecutiveCellTypes())
415     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
416   return new MEDCouplingUMeshCellByTypeEntry(this);
417 }
418
419 /*!
420  * Returns a set of all cell types available in \a this mesh.
421  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
422  * \warning this method does not throw any exception even if \a this is not defined.
423  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
424  */
425 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
426 {
427   return _types;
428 }
429
430 /*!
431  * This method returns the sorted list of geometric types in \a this.
432  * 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
433  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
434  *
435  * \throw if connectivity in \a this is not correctly defined.
436  *
437  * \sa MEDCouplingMesh::getAllGeoTypes
438  */
439 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
440 {
441   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
442   checkConnectivityFullyDefined();
443   mcIdType nbOfCells=getNumberOfCells();
444   if(nbOfCells==0)
445     return ret;
446   if(getNodalConnectivityArrayLen()<1)
447     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
448   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
449   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
450   for(mcIdType i=1;i<nbOfCells;i++,ci++)
451     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
452       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
453   return ret;
454 }
455
456 /*!
457  * This method is a method that compares \a this and \a other.
458  * This method compares \b all attributes, even names and component names.
459  */
460 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
461 {
462   if(!other)
463     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
464   std::ostringstream oss; oss.precision(15);
465   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
466   if(!otherC)
467     {
468       reason="mesh given in input is not castable in MEDCouplingUMesh !";
469       return false;
470     }
471   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
472     return false;
473   if(_mesh_dim!=otherC->_mesh_dim)
474     {
475       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
476       reason=oss.str();
477       return false;
478     }
479   if(_types!=otherC->_types)
480     {
481       oss << "umesh geometric type mismatch :\nThis geometric types are :";
482       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
483         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
484       oss << "\nOther geometric types are :";
485       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
486         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
487       reason=oss.str();
488       return false;
489     }
490   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
491     if(_nodal_connec==0 || otherC->_nodal_connec==0)
492       {
493         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
494         return false;
495       }
496   if(_nodal_connec!=otherC->_nodal_connec)
497     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
498       {
499         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
500         return false;
501       }
502   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
503     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
504       {
505         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
506         return false;
507       }
508   if(_nodal_connec_index!=otherC->_nodal_connec_index)
509     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
510       {
511         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
512         return false;
513       }
514   return true;
515 }
516
517 /*!
518  * Checks if data arrays of this mesh (node coordinates, nodal
519  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
520  * not considered.
521  *  \param [in] other - the mesh to compare with.
522  *  \param [in] prec - precision value used to compare node coordinates.
523  *  \return bool - \a true if the two meshes are same.
524  */
525 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
526 {
527   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
528   if(!otherC)
529     return false;
530   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
531     return false;
532   if(_mesh_dim!=otherC->_mesh_dim)
533     return false;
534   if(_types!=otherC->_types)
535     return false;
536   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
537     if(_nodal_connec==0 || otherC->_nodal_connec==0)
538       return false;
539   if(_nodal_connec!=otherC->_nodal_connec)
540     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
541       return false;
542   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
543     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
544       return false;
545   if(_nodal_connec_index!=otherC->_nodal_connec_index)
546     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
547       return false;
548   return true;
549 }
550
551 /*!
552  * Checks if \a this and \a other meshes are geometrically equivalent with high
553  * probability, else an exception is thrown. The meshes are considered equivalent if
554  * (1) meshes contain the same number of nodes and the same number of elements of the
555  * same types (2) three cells of the two meshes (first, last and middle) are based
556  * on coincident nodes (with a specified precision).
557  *  \param [in] other - the mesh to compare with.
558  *  \param [in] prec - the precision used to compare nodes of the two meshes.
559  *  \throw If the two meshes do not match.
560  */
561 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
562 {
563   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
564   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
565   if(!otherC)
566     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
567 }
568
569 /*!
570  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
571  * cells each node belongs to.
572  * \warning For speed reasons, this method does not check if node ids in the nodal
573  *          connectivity correspond to the size of node coordinates array.
574  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
575  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
576  *        dividing cell ids in \a revNodal into groups each referring to one
577  *        node. Its every element (except the last one) is an index pointing to the
578  *         first id of a group of cells. For example cells sharing the node #1 are
579  *        described by following range of indices:
580  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
581  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
582  *        Number of cells sharing the *i*-th node is
583  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
584  * \throw If the coordinates array is not set.
585  * \throw If the nodal connectivity of cells is not defined.
586  *
587  * \if ENABLE_EXAMPLES
588  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
589  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
590  * \endif
591  */
592 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
593 {
594   checkFullyDefined();
595   mcIdType nbOfNodes(getNumberOfNodes());
596   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
597   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
598   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
599   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
600   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
601   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
602     {
603       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
604       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
605         if(*iter>=0)//for polyhedrons
606           {
607             nbOfEltsInRevNodal++;
608             revNodalIndxPtr[(*iter)+1]++;
609           }
610     }
611   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
612   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
613   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
614   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
615   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
616     {
617       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
618       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
619       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
620         if(*iter>=0)//for polyhedrons
621           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
622     }
623 }
624
625 /*!
626  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
627  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
628  * describing correspondence between cells of \a this and the result meshes are
629  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
630  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
631  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
632  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
633  * \warning For speed reasons, this method does not check if node ids in the nodal
634  *          connectivity correspond to the size of node coordinates array.
635  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
636  *          to write this mesh to the MED file, its cells must be sorted using
637  *          sortCellsInMEDFileFrmt().
638  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
639  *         each cell of \a this mesh.
640  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
641  *        dividing cell ids in \a desc into groups each referring to one
642  *        cell of \a this mesh. Its every element (except the last one) is an index
643  *        pointing to the first id of a group of cells. For example cells of the
644  *        result mesh bounding the cell #1 of \a this mesh are described by following
645  *        range of indices:
646  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
647  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
648  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
649  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
650  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
651  *         by each cell of the result mesh.
652  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
653  *        in the result mesh,
654  *        dividing cell ids in \a revDesc into groups each referring to one
655  *        cell of the result mesh the same way as \a descIndx divides \a desc.
656  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
657  *        delete this mesh using decrRef() as it is no more needed.
658  *  \throw If the coordinates array is not set.
659  *  \throw If the nodal connectivity of cells is node defined.
660  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
661  *         revDescIndx == NULL.
662  *
663  *  \if ENABLE_EXAMPLES
664  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
665  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
666  *  \endif
667  * \sa buildDescendingConnectivity2()
668  */
669 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
670 {
671   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
672 }
673
674 /*!
675  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
676  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
677  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
678  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
679  * \sa MEDCouplingUMesh::buildDescendingConnectivity
680  */
681 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
682 {
683   checkFullyDefined();
684   if(getMeshDimension()!=3)
685     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
686   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
687 }
688
689 /*!
690  * 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.
691  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
692  * 
693  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697    checkFullyDefined();
698    switch(getMeshDimension())
699      {
700      case 2:
701        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
702      case 3:
703        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
704      default:
705        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
706      }
707 }
708
709 /*!
710  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
711  * this->getMeshDimension(), that bound cells of \a this mesh. In
712  * addition arrays describing correspondence between cells of \a this and the result
713  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
714  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
715  *  mesh. This method differs from buildDescendingConnectivity() in that apart
716  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
717  * result meshes. So a positive id means that order of nodes in corresponding cells
718  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
719  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
720  * i.e. cell ids are one-based.
721  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
722  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
723  * \warning For speed reasons, this method does not check if node ids in the nodal
724  *          connectivity correspond to the size of node coordinates array.
725  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
726  *          to write this mesh to the MED file, its cells must be sorted using
727  *          sortCellsInMEDFileFrmt().
728  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
729  *         each cell of \a this mesh.
730  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
731  *        dividing cell ids in \a desc into groups each referring to one
732  *        cell of \a this mesh. Its every element (except the last one) is an index
733  *        pointing to the first id of a group of cells. For example cells of the
734  *        result mesh bounding the cell #1 of \a this mesh are described by following
735  *        range of indices:
736  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
737  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
738  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
739  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
740  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
741  *         by each cell of the result mesh.
742  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
743  *        in the result mesh,
744  *        dividing cell ids in \a revDesc into groups each referring to one
745  *        cell of the result mesh the same way as \a descIndx divides \a desc.
746  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
747  *        shares the node coordinates array with \a this mesh. The caller is to
748  *        delete this mesh using decrRef() as it is no more needed.
749  *  \throw If the coordinates array is not set.
750  *  \throw If the nodal connectivity of cells is node defined.
751  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
752  *         revDescIndx == NULL.
753  *
754  *  \if ENABLE_EXAMPLES
755  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
756  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
757  *  \endif
758  * \sa buildDescendingConnectivity()
759  */
760 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
761 {
762   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
763 }
764
765 /*!
766  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
767  * For speed reasons no check of this will be done. This method calls
768  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
769  * This method lists cell by cell in \b this which are its neighbors. To compute the result
770  * only connectivities are considered.
771  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
772  * The format of return is hence \ref numbering-indirect.
773  *
774  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
775  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
776  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
777  * is equal to the last values in \b neighborsIndx.
778  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
779  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
780  */
781 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
782 {
783   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
784   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
785   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
786   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
787   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
788   meshDM1=0;
789   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
790 }
791
792 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI, MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
793 {
794   if(!nodeNeigh || !nodeNeighI)
795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
796   checkConsistencyLight();
797   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
798   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
799   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
800   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
801   mcIdType nbCells=getNumberOfCells();
802   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
803   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
804   for(mcIdType i=0;i<nbCells;i++)
805     {
806       std::set<mcIdType> s;
807       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
808         if(*it>=0)
809           s.insert(ne+nei[*it],ne+nei[*it+1]);
810       s.erase(i);
811       cellNeigh->insertAtTheEnd(s.begin(),s.end());
812       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
813     }
814 }
815
816 /*!
817  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
818  * of MEDCouplingUMesh::computeNeighborsOfCells.
819  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
820  * typically the case to extract a set a neighbours,
821  * excluding a set of meshdim-1 cells in input descending connectivity.
822  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
823  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
824  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
825  * are considered.
826  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
827  *
828  * \param [in] desc descending connectivity array.
829  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
830  * \param [in] revDesc reverse descending connectivity array.
831  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
832  * \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
833  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
834  * \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.
835  */
836 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
837                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
838 {
839   if(!desc || !descIndx || !revDesc || !revDescIndx)
840     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
841   const mcIdType *descPtr=desc->begin();
842   const mcIdType *descIPtr=descIndx->begin();
843   const mcIdType *revDescPtr=revDesc->begin();
844   const mcIdType *revDescIPtr=revDescIndx->begin();
845   //
846   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
847   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
848   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
849   mcIdType *out1Ptr=out1->getPointer();
850   *out1Ptr++=0;
851   out0->reserve(desc->getNumberOfTuples());
852   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
853     {
854       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
855         {
856           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
857           s.erase(i);
858           out0->insertAtTheEnd(s.begin(),s.end());
859         }
860       *out1Ptr=out0->getNumberOfTuples();
861     }
862   neighbors=out0.retn();
863   neighborsIndx=out1.retn();
864 }
865
866 /*!
867  * Explodes \a this into edges whatever its dimension.
868  */
869 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
870 {
871   checkFullyDefined();
872   int mdim(getMeshDimension());
873   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
874   MCAuto<MEDCouplingUMesh> mesh1D;
875   switch(mdim)
876   {
877     case 3:
878       {
879         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
880         break;
881       }
882     case 2:
883       {
884         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
885         break;
886       }
887     default:
888       {
889         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
890       }
891   }
892   return mesh1D;
893 }
894
895 /*!
896  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
897  * For speed reasons no check of this will be done. This method calls
898  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
899  * This method lists node by node in \b this which are its neighbors. To compute the result
900  * only connectivities are considered.
901  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
902  *
903  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
904  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
905  * parameter allows to select the right part in this array (\ref numbering-indirect).
906  * The number of tuples is equal to the last values in \b neighborsIndx.
907  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
908  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
909  *
910  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
911  */
912 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
913 {
914   checkFullyDefined();
915   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
916   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
917   MCConstAuto<MEDCouplingUMesh> mesh1D;
918   switch(mdim)
919   {
920     case 3:
921       {
922         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
923         break;
924       }
925     case 2:
926       {
927         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
928         break;
929       }
930     case 1:
931       {
932         mesh1D.takeRef(this);
933         break;
934       }
935     default:
936       {
937         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
938       }
939   }
940   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
941   mesh1D->getReverseNodalConnectivity(desc,descIndx);
942   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
943   ret0->alloc(desc->getNumberOfTuples(),1);
944   mcIdType *r0Pt(ret0->getPointer());
945   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
946   for(mcIdType i=0;i<nbNodes;i++,rni++)
947     {
948       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
949         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
950     }
951   neighbors=ret0.retn();
952   neighborsIdx=descIndx.retn();
953 }
954
955 /*!
956  * 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.
957  * 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.
958  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
959  *
960  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
961  */
962 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
963 {
964   checkFullyDefined();
965   mcIdType nbOfNodes(getNumberOfNodes());
966   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
967   mcIdType nbOfCells=getNumberOfCells();
968   std::vector< std::set<mcIdType> > st0(nbOfNodes);
969   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
970     {
971       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
972       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
973       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
974         st0[*iter2].insert(s.begin(),s.end());
975     }
976   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
977   {
978     mcIdType *neighIdx(neighborsIdx->getPointer());
979     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
980       {
981         if ((*it).empty())
982           neighIdx[1]=neighIdx[0];
983         else
984           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
985       }
986   }
987   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
988   {
989     const mcIdType *neighIdx(neighborsIdx->begin());
990     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
991     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
992       {
993         std::set<mcIdType> s(*it); s.erase(nodeId);
994         std::copy(s.begin(),s.end(),neigh+*neighIdx);
995       }
996   }
997 }
998
999 /*!
1000  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1001  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1002  * array of cell ids. Pay attention that after conversion all algorithms work slower
1003  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1004  * conversion due presence of invalid ids in the array of cells to convert, as a
1005  * result \a this mesh contains some already converted elements. In this case the 2D
1006  * mesh remains valid but 3D mesh becomes \b inconsistent!
1007  *  \warning This method can significantly modify the order of geometric types in \a this,
1008  *          hence, to write this mesh to the MED file, its cells must be sorted using
1009  *          sortCellsInMEDFileFrmt().
1010  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1011  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1012  *         cellIdsToConvertBg.
1013  *  \throw If the coordinates array is not set.
1014  *  \throw If the nodal connectivity of cells is node defined.
1015  *  \throw If dimension of \a this mesh is not either 2 or 3.
1016  *
1017  *  \if ENABLE_EXAMPLES
1018  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1019  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1020  *  \endif
1021  */
1022 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1023 {
1024   checkFullyDefined();
1025   int dim=getMeshDimension();
1026   if(dim<2 || dim>3)
1027     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1028   mcIdType nbOfCells=getNumberOfCells();
1029   if(dim==2)
1030     {
1031       const mcIdType *connIndex=_nodal_connec_index->begin();
1032       mcIdType *conn=_nodal_connec->getPointer();
1033       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1034         {
1035           if(*iter>=0 && *iter<nbOfCells)
1036             {
1037               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1038               if(!cm.isQuadratic())
1039                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1040               else
1041                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1042             }
1043           else
1044             {
1045               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1046               oss << " in range [0," << nbOfCells << ") !";
1047               throw INTERP_KERNEL::Exception(oss.str());
1048             }
1049         }
1050     }
1051   else
1052     {
1053       mcIdType *connIndex(_nodal_connec_index->getPointer());
1054       const mcIdType *connOld(_nodal_connec->getConstPointer());
1055       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1056       std::vector<bool> toBeDone(nbOfCells,false);
1057       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1058         {
1059           if(*iter>=0 && *iter<nbOfCells)
1060             toBeDone[*iter]=true;
1061           else
1062             {
1063               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1064               oss << " in range [0," << nbOfCells << ") !";
1065               throw INTERP_KERNEL::Exception(oss.str());
1066             }
1067         }
1068       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1069         {
1070           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1071           mcIdType lgthOld(posP1-pos-1);
1072           if(toBeDone[cellId])
1073             {
1074               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1075               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1076               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1077               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1078               for(unsigned j=0;j<nbOfFaces;j++)
1079                 {
1080                   INTERP_KERNEL::NormalizedCellType type;
1081                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1082                   work+=offset;
1083                   *work++=-1;
1084                 }
1085               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1086               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1087               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1088               delete [] tmp;
1089             }
1090           else
1091             {
1092               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1093               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1094             }
1095         }
1096       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1097     }
1098   computeTypes();
1099 }
1100
1101 /*!
1102  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1103  * polyhedrons (if \a this is a 3D mesh).
1104  *  \warning As this method is purely for user-friendliness and no optimization is
1105  *          done to avoid construction of a useless vector, this method can be costly
1106  *          in memory.
1107  *  \throw If the coordinates array is not set.
1108  *  \throw If the nodal connectivity of cells is node defined.
1109  *  \throw If dimension of \a this mesh is not either 2 or 3.
1110  */
1111 void MEDCouplingUMesh::convertAllToPoly()
1112 {
1113   mcIdType nbOfCells=getNumberOfCells();
1114   std::vector<mcIdType> cellIds(nbOfCells);
1115   for(mcIdType i=0;i<nbOfCells;i++)
1116     cellIds[i]=i;
1117   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1118 }
1119
1120 /*!
1121  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1122  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1123  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1124  * base facet of the volume and the second half of nodes describes an opposite facet
1125  * having the same number of nodes as the base one. This method converts such
1126  * connectivity to a valid polyhedral format where connectivity of each facet is
1127  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1128  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1129  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1130  * a correct orientation of the first facet of a polyhedron, else orientation of a
1131  * corrected cell is reverse.<br>
1132  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1133  * it releases the user from boring description of polyhedra connectivity in the valid
1134  * format.
1135  *  \throw If \a this->getMeshDimension() != 3.
1136  *  \throw If \a this->getSpaceDimension() != 3.
1137  *  \throw If the nodal connectivity of cells is not defined.
1138  *  \throw If the coordinates array is not set.
1139  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1140  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1141  *
1142  *  \if ENABLE_EXAMPLES
1143  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1144  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1145  *  \endif
1146  */
1147 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1148 {
1149   checkFullyDefined();
1150   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1151     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1152   mcIdType nbOfCells=getNumberOfCells();
1153   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1154   newCi->alloc(nbOfCells+1,1);
1155   mcIdType *newci=newCi->getPointer();
1156   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1157   const mcIdType *c=_nodal_connec->getConstPointer();
1158   newci[0]=0;
1159   for(mcIdType i=0;i<nbOfCells;i++)
1160     {
1161       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1162       if(type==INTERP_KERNEL::NORM_POLYHED)
1163         {
1164           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1165             {
1166               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1167               throw INTERP_KERNEL::Exception(oss.str());
1168             }
1169           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1170           if(n2%2!=0)
1171             {
1172               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 !";
1173               throw INTERP_KERNEL::Exception(oss.str());
1174             }
1175           mcIdType n1=ToIdType(n2/2);
1176           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)
1177         }
1178       else
1179         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1180     }
1181   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1182   newC->alloc(newci[nbOfCells],1);
1183   mcIdType *newc=newC->getPointer();
1184   for(mcIdType i=0;i<nbOfCells;i++)
1185     {
1186       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1187       if(type==INTERP_KERNEL::NORM_POLYHED)
1188         {
1189           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1190           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1191           *newc++=-1;
1192           for(std::size_t j=0;j<n1;j++)
1193             {
1194               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1195               newc[n1+5*j]=-1;
1196               newc[n1+5*j+1]=c[ci[i]+1+j];
1197               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1198               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1199               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1200             }
1201           newc+=n1*6;
1202         }
1203       else
1204         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1205     }
1206   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1207   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1208 }
1209
1210
1211 /*!
1212  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1213  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1214  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1215  *          to write this mesh to the MED file, its cells must be sorted using
1216  *          sortCellsInMEDFileFrmt().
1217  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1218  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1219  * \return \c true if at least one cell has been converted, \c false else. In the
1220  *         last case the nodal connectivity remains unchanged.
1221  * \throw If the coordinates array is not set.
1222  * \throw If the nodal connectivity of cells is not defined.
1223  * \throw If \a this->getMeshDimension() < 0.
1224  */
1225 bool MEDCouplingUMesh::unPolyze()
1226 {
1227   checkFullyDefined();
1228   int mdim=getMeshDimension();
1229   if(mdim<0)
1230     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1231   if(mdim<=1)
1232     return false;
1233   mcIdType nbOfCells=getNumberOfCells();
1234   if(nbOfCells<1)
1235     return false;
1236   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1237   mcIdType *conn=_nodal_connec->getPointer();
1238   mcIdType *index=_nodal_connec_index->getPointer();
1239   mcIdType posOfCurCell=0;
1240   mcIdType newPos=0;
1241   mcIdType lgthOfCurCell;
1242   bool ret=false;
1243   for(mcIdType i=0;i<nbOfCells;i++)
1244     {
1245       lgthOfCurCell=index[i+1]-posOfCurCell;
1246       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1247       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1248       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1249       mcIdType newLgth=0;
1250       if(cm.isDynamic())
1251         {
1252           switch(cm.getDimension())
1253           {
1254             case 2:
1255               {
1256                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1257                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1258                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1259                 break;
1260               }
1261             case 3:
1262               {
1263                 mcIdType nbOfFaces,lgthOfPolyhConn;
1264                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1265                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1266                 break;
1267               }
1268          /*   case 1:  // Not supported yet
1269               {
1270                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1271                 break;
1272               }
1273          */
1274           }
1275           ret=ret || (newType!=type);
1276           conn[newPos]=newType;
1277           newPos+=newLgth+1;
1278           posOfCurCell=index[i+1];
1279           index[i+1]=newPos;
1280         }
1281       else
1282         {
1283           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1284           newPos+=lgthOfCurCell;
1285           posOfCurCell+=lgthOfCurCell;
1286           index[i+1]=newPos;
1287         }
1288     }
1289   if(newPos!=initMeshLgth)
1290     _nodal_connec->reAlloc(newPos);
1291   if(ret)
1292     computeTypes();
1293   return ret;
1294 }
1295
1296 /*!
1297  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1298  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1299  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1300  *
1301  * \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
1302  *             precision.
1303  */
1304 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1305 {
1306   checkFullyDefined();
1307   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1308     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1309   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1310   coords->recenterForMaxPrecision(eps);
1311   //
1312   mcIdType nbOfCells=getNumberOfCells();
1313   const mcIdType *conn=_nodal_connec->getConstPointer();
1314   const mcIdType *index=_nodal_connec_index->getConstPointer();
1315   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1316   connINew->alloc(nbOfCells+1,1);
1317   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1318   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1319   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1320   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1321   bool changed=false;
1322   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1323     {
1324       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1325         {
1326           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1327           changed=true;
1328         }
1329       else
1330         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1331       *connINewPtr=connNew->getNumberOfTuples();
1332     }
1333   if(changed)
1334     setConnectivity(connNew,connINew,false);
1335 }
1336
1337 /*!
1338  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1339  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1340  * the format of the returned DataArrayIdType instance.
1341  *
1342  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1343  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1344  */
1345 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1346 {
1347   checkConnectivityFullyDefined();
1348   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1349   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1350   std::vector<bool> retS(maxElt,false);
1351   computeNodeIdsAlg(retS);
1352   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1353 }
1354
1355 /*!
1356  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1357  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1358  */
1359 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1360 {
1361   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1362            nbOfCells=getNumberOfCells();
1363   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1364   for(mcIdType i=0;i<nbOfCells;i++)
1365     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1366       if(conn[j]>=0)
1367         {
1368           if(conn[j]<nbOfNodes)
1369             nodeIdsInUse[conn[j]]=true;
1370           else
1371             {
1372               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1373               throw INTERP_KERNEL::Exception(oss.str());
1374             }
1375         }
1376 }
1377
1378 /// @cond INTERNAL
1379
1380 struct MEDCouplingAccVisit
1381 {
1382   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1383   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1384   mcIdType _new_nb_of_nodes;
1385 };
1386
1387 /// @endcond
1388
1389 /*!
1390  * Finds nodes not used in any cell and returns an array giving a new id to every node
1391  * by excluding the unused nodes, for which the array holds -1. The result array is
1392  * a mapping in "Old to New" mode.
1393  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1394  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1395  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1396  *          if the node is unused or a new id else. The caller is to delete this
1397  *          array using decrRef() as it is no more needed.
1398  *  \throw If the coordinates array is not set.
1399  *  \throw If the nodal connectivity of cells is not defined.
1400  *  \throw If the nodal connectivity includes an invalid id.
1401  *
1402  *  \if ENABLE_EXAMPLES
1403  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1404  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1405  *  \endif
1406  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1407  */
1408 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1409 {
1410   nbrOfNodesInUse=-1;
1411   mcIdType nbOfNodes(getNumberOfNodes());
1412   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1413   ret->alloc(nbOfNodes,1);
1414   mcIdType *traducer=ret->getPointer();
1415   std::fill(traducer,traducer+nbOfNodes,-1);
1416   mcIdType nbOfCells=getNumberOfCells();
1417   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1418   const mcIdType *conn=_nodal_connec->getConstPointer();
1419   for(mcIdType i=0;i<nbOfCells;i++)
1420     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1421       if(conn[j]>=0)
1422         {
1423           if(conn[j]<nbOfNodes)
1424             traducer[conn[j]]=1;
1425           else
1426             {
1427               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1428               throw INTERP_KERNEL::Exception(oss.str());
1429             }
1430         }
1431   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1432   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1433   return ret.retn();
1434 }
1435
1436 /*!
1437  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1438  * For each cell in \b this the number of nodes constituting cell is computed.
1439  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1440  * So for pohyhedrons some nodes can be counted several times in the returned result.
1441  *
1442  * \return a newly allocated array
1443  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1444  */
1445 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1446 {
1447   checkConnectivityFullyDefined();
1448   mcIdType nbOfCells=getNumberOfCells();
1449   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1450   ret->alloc(nbOfCells,1);
1451   mcIdType *retPtr=ret->getPointer();
1452   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1453   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1454   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1455     {
1456       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1457         *retPtr=connI[i+1]-connI[i]-1;
1458       else
1459         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1460     }
1461   return ret.retn();
1462 }
1463
1464 /*!
1465  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1466  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1467  *
1468  * \return DataArrayIdType * - new object to be deallocated by the caller.
1469  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1470  */
1471 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1472 {
1473   checkConnectivityFullyDefined();
1474   mcIdType nbOfCells=getNumberOfCells();
1475   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1476   ret->alloc(nbOfCells,1);
1477   mcIdType *retPtr=ret->getPointer();
1478   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1479   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1480   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1481     {
1482       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1483       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1484         *retPtr=ToIdType(s.size());
1485       else
1486         {
1487           s.erase(-1);
1488           *retPtr=ToIdType(s.size());
1489         }
1490     }
1491   return ret.retn();
1492 }
1493
1494 /*!
1495  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1496  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1497  *
1498  * \return a newly allocated array
1499  */
1500 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1501 {
1502   checkConnectivityFullyDefined();
1503   mcIdType nbOfCells=getNumberOfCells();
1504   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1505   ret->alloc(nbOfCells,1);
1506   mcIdType *retPtr=ret->getPointer();
1507   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1508   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1509   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1510     {
1511       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1512       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1513     }
1514   return ret.retn();
1515 }
1516
1517 /*!
1518  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1519  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1520  * array mean that the corresponding old node is no more used.
1521  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1522  *           this->getNumberOfNodes() before call of this method. The caller is to
1523  *           delete this array using decrRef() as it is no more needed.
1524  *  \throw If the coordinates array is not set.
1525  *  \throw If the nodal connectivity of cells is not defined.
1526  *  \throw If the nodal connectivity includes an invalid id.
1527  *  \sa areAllNodesFetched
1528  *
1529  *  \if ENABLE_EXAMPLES
1530  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1531  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1532  *  \endif
1533  */
1534 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1535 {
1536   return MEDCouplingPointSet::zipCoordsTraducer();
1537 }
1538
1539 /*!
1540  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1541  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1542  */
1543 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1544 {
1545   switch(compType)
1546   {
1547     case 0:
1548       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1549     case 1:
1550       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1551     case 2:
1552       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1553     case 3:
1554       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1555     case 7:
1556       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1557   }
1558   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1559 }
1560
1561 /*!
1562  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1563  */
1564 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1565 {
1566   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1567     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1568   return 0;
1569 }
1570
1571 /*!
1572  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1573  */
1574 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1575 {
1576   mcIdType sz=connI[cell1+1]-connI[cell1];
1577   if(sz==connI[cell2+1]-connI[cell2])
1578     {
1579       if(conn[connI[cell1]]==conn[connI[cell2]])
1580         {
1581           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1582           unsigned dim=cm.getDimension();
1583           if(dim!=3)
1584             {
1585               if(dim!=1)
1586                 {
1587                   mcIdType sz1=2*(sz-1);
1588                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1589                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1590                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1591                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1592                   return work!=tmp+sz1?1:0;
1593                 }
1594               else
1595                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1596             }
1597           else
1598             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1599         }
1600     }
1601   return 0;
1602 }
1603
1604 /*!
1605  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1606  */
1607 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1608 {
1609   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1610     {
1611       if(conn[connI[cell1]]==conn[connI[cell2]])
1612         {
1613           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1614           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1615           return s1==s2?1:0;
1616         }
1617     }
1618   return 0;
1619 }
1620
1621 /*!
1622  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1623  */
1624 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1625 {
1626   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1627     {
1628       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1629       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1630       return s1==s2?1:0;
1631     }
1632   return 0;
1633 }
1634
1635 /*!
1636  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1637  */
1638 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1639 {
1640   mcIdType sz=connI[cell1+1]-connI[cell1];
1641   if(sz==connI[cell2+1]-connI[cell2])
1642     {
1643       if(conn[connI[cell1]]==conn[connI[cell2]])
1644         {
1645           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1646           unsigned dim=cm.getDimension();
1647           if(dim!=3)
1648             {
1649               if(dim!=1)
1650                 {
1651                   mcIdType sz1=2*(sz-1);
1652                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1653                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1654                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1655                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1656                   if(work!=tmp+sz1)
1657                     return 1;
1658                   else
1659                     {
1660                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1661                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1662                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1663                         return 2;
1664                       else
1665                         return 0;
1666                     }
1667                 }
1668               else
1669                 {//case of SEG2 and SEG3
1670                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1671                     return 1;
1672                   if(!cm.isQuadratic())
1673                     {
1674                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1675                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1676                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1677                         return 2;
1678                       return 0;
1679                     }
1680                   else
1681                     {
1682                       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])
1683                         return 2;
1684                       return 0;
1685                     }
1686                 }
1687             }
1688           else
1689             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1690         }
1691     }
1692   return 0;
1693 }
1694
1695
1696 /*!
1697  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1698  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1699  * 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.
1700  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1701  * This method is time consuming.
1702  *
1703  * \param [in] compType input specifying the technique used to compare cells each other.
1704  *   - 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.
1705  *   - 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)
1706  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1707  *   - 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
1708  * can be used for users not sensitive to orientation of cell
1709  * \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.
1710  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1711  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1712  *
1713  */
1714 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1715 {
1716   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1717   getReverseNodalConnectivity(revNodal,revNodalI);
1718   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1719 }
1720
1721 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1722                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1723 {
1724   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1725   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1726   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1727   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1728   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1729   std::vector<bool> isFetched(nbOfCells,false);
1730   if(startCellId==0)
1731     {
1732       for(mcIdType i=startCellId;i<nbOfCells;i++)
1733         {
1734           if(!isFetched[i])
1735             {
1736               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));
1737               std::vector<mcIdType> v,v2;
1738               if(connOfNode!=connPtr+connIPtr[i+1])
1739                 {
1740                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1741                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1742                   connOfNode++;
1743                 }
1744               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1745                 if(*connOfNode>=0)
1746                   {
1747                     v=v2;
1748                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1749                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1750                     v2.resize(std::distance(v2.begin(),it));
1751                   }
1752               if(v2.size()>1)
1753                 {
1754                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1755                     {
1756                       mcIdType pos=commonCellsI->back();
1757                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1758                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1759                         isFetched[*it]=true;
1760                     }
1761                 }
1762             }
1763         }
1764     }
1765   else
1766     {
1767       for(mcIdType i=startCellId;i<nbOfCells;i++)
1768         {
1769           if(!isFetched[i])
1770             {
1771               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));
1772               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1773               std::vector<mcIdType> v,v2;
1774               if(connOfNode!=connPtr+connIPtr[i+1])
1775                 {
1776                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1777                   connOfNode++;
1778                 }
1779               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1780                 if(*connOfNode>=0)
1781                   {
1782                     v=v2;
1783                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1784                     v2.resize(std::distance(v2.begin(),it));
1785                   }
1786               // v2 contains now candidates. Problem candidates are sorted using id rank.
1787               if(v2.size()>1)
1788                 {
1789                   if(v2[0]!=i)
1790                   {
1791                     auto it(std::find(v2.begin(),v2.end(),i));
1792                     std::swap(*v2.begin(),*it);
1793                   }
1794                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1795                     {
1796                       mcIdType newPos(commonCells->getNumberOfTuples());
1797                       mcIdType pos(commonCellsI->back());
1798                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1799                       commonCellsI->pushBackSilent(newPos);
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   commonCellsArr=commonCells.retn();
1808   commonCellsIArr=commonCellsI.retn();
1809 }
1810
1811 /*!
1812  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1813  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1814  * than \a this->getNumberOfCells() in the returned array means that there is no
1815  * corresponding cell in \a this mesh.
1816  * It is expected that \a this and \a other meshes share the same node coordinates
1817  * array, if it is not so an exception is thrown.
1818  *  \param [in] other - the mesh to compare with.
1819  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1820  *         valid values [0,1,2], see zipConnectivityTraducer().
1821  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1822  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1823  *         values. The caller is to delete this array using
1824  *         decrRef() as it is no more needed.
1825  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1826  *         mesh.
1827  *
1828  *  \if ENABLE_EXAMPLES
1829  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1830  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1831  *  \endif
1832  *  \sa checkDeepEquivalOnSameNodesWith()
1833  *  \sa checkGeoEquivalWith()
1834  */
1835 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1836 {
1837   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1838   mcIdType nbOfCells=getNumberOfCells();
1839   static const int possibleCompType[]={0,1,2};
1840   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1841     {
1842       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1843       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1844       oss << " !";
1845       throw INTERP_KERNEL::Exception(oss.str());
1846     }
1847   //
1848   if(other->getNumberOfCells()==0)
1849   {
1850     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1851     return true;
1852   }
1853   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1854   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1855   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1856   mcIdType newNbOfCells=-1;
1857   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1858   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1859   mcIdType maxPart(p0->getMaxValueInArray());
1860   bool ret(maxPart==newNbOfCells-1);
1861   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1862   // fill p1 array in case of presence of cells in other not in this
1863   mcIdType *pt(p1->getPointer());
1864   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1865     pt[i+1] = i+1;
1866   //
1867   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1868   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1869   arr = p2.retn();
1870   return ret;
1871 }
1872
1873 /*!
1874  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1875  * This method tries to determine if \b other is fully included in \b this.
1876  * The main difference is that this method is not expected to throw exception.
1877  * This method has two outputs :
1878  *
1879  * \param other other mesh
1880  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1881  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1882  */
1883 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1884 {
1885   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1886   DataArrayIdType *commonCells=0,*commonCellsI=0;
1887   mcIdType thisNbCells=getNumberOfCells();
1888   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1889   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1890   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1891   mcIdType otherNbCells=other->getNumberOfCells();
1892   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1893   arr2->alloc(otherNbCells,1);
1894   arr2->fillWithZero();
1895   mcIdType *arr2Ptr=arr2->getPointer();
1896   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1897   for(mcIdType i=0;i<nbOfCommon;i++)
1898     {
1899       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1900       if(start<thisNbCells)
1901         {
1902           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1903             {
1904               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1905               mcIdType val=std::abs(commonCellsPtr[j])-1;
1906               if(val>=thisNbCells)
1907                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1908             }
1909         }
1910     }
1911   arr2->setName(other->getName());
1912   if(arr2->presenceOfValue(0))
1913     return false;
1914   arr=arr2.retn();
1915   return true;
1916 }
1917
1918 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1919 {
1920   if(!other)
1921     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1922   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1923   if(!otherC)
1924     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1925   std::vector<const MEDCouplingUMesh *> ms(2);
1926   ms[0]=this;
1927   ms[1]=otherC;
1928   return MergeUMeshesOnSameCoords(ms);
1929 }
1930
1931 /*!
1932  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1933  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1934  * cellIds is not given explicitly but by a range python like.
1935  *
1936  * \param start starting ID
1937  * \param end end ID (excluded)
1938  * \param step step size
1939  * \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.
1940  * \return a newly allocated
1941  *
1942  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1943  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1944  */
1945 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1946 {
1947   if(getMeshDimension()!=-1)
1948     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1949   else
1950     {
1951       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1952       if(newNbOfCells!=1)
1953         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1954       if(start!=0)
1955         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1956       incrRef();
1957       return const_cast<MEDCouplingUMesh *>(this);
1958     }
1959 }
1960
1961 /*!
1962  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1963  * The result mesh shares or not the node coordinates array with \a this mesh depending
1964  * on \a keepCoords parameter.
1965  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1966  *           to write this mesh to the MED file, its cells must be sorted using
1967  *           sortCellsInMEDFileFrmt().
1968  *  \param [in] begin - an array of cell ids to include to the new mesh.
1969  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
1970  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1971  *         array of \a this mesh, else "free" nodes are removed from the result mesh
1972  *         by calling zipCoords().
1973  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1974  *         to delete this mesh using decrRef() as it is no more needed.
1975  *  \throw If the coordinates array is not set.
1976  *  \throw If the nodal connectivity of cells is not defined.
1977  *  \throw If any cell id in the array \a begin is not valid.
1978  *
1979  *  \if ENABLE_EXAMPLES
1980  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1981  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
1982  *  \endif
1983  */
1984 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1985 {
1986   if(getMeshDimension()!=-1)
1987     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1988   else
1989     {
1990       if(end-begin!=1)
1991         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1992       if(begin[0]!=0)
1993         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1994       incrRef();
1995       return const_cast<MEDCouplingUMesh *>(this);
1996     }
1997 }
1998
1999 /*!
2000  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2001  *
2002  * 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.
2003  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2004  * The number of cells of \b this will remain the same with this method.
2005  *
2006  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2007  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2008  * \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 ).
2009  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2010  */
2011 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2012 {
2013   checkConnectivityFullyDefined();
2014   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2015   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2016     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2017   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2018     {
2019       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2020       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2021       throw INTERP_KERNEL::Exception(oss.str());
2022     }
2023   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2024   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2025     {
2026       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2027       throw INTERP_KERNEL::Exception(oss.str());
2028     }
2029   mcIdType nbOfCells(getNumberOfCells());
2030   bool easyAssign(true);
2031   const mcIdType *connI(_nodal_connec_index->begin());
2032   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2033   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2034     {
2035       if(*it>=0 && *it<nbOfCells)
2036         {
2037           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2038         }
2039       else
2040         {
2041           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2042           throw INTERP_KERNEL::Exception(oss.str());
2043         }
2044     }
2045   if(easyAssign)
2046     {
2047       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2048       computeTypes();
2049     }
2050   else
2051     {
2052       DataArrayIdType *arrOut=0,*arrIOut=0;
2053       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2054                                                arrOut,arrIOut);
2055       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2056       setConnectivity(arrOut,arrIOut,true);
2057     }
2058 }
2059
2060 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2061 {
2062   checkConnectivityFullyDefined();
2063   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2064   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2065     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2066   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2069       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2070       throw INTERP_KERNEL::Exception(oss.str());
2071     }
2072   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2073   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2074     {
2075       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2076       throw INTERP_KERNEL::Exception(oss.str());
2077     }
2078   mcIdType nbOfCells=getNumberOfCells();
2079   bool easyAssign=true;
2080   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2081   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2082   mcIdType it=start;
2083   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2084     {
2085       if(it>=0 && it<nbOfCells)
2086         {
2087           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2088         }
2089       else
2090         {
2091           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2092           throw INTERP_KERNEL::Exception(oss.str());
2093         }
2094     }
2095   if(easyAssign)
2096     {
2097       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2098       computeTypes();
2099     }
2100   else
2101     {
2102       DataArrayIdType *arrOut=0,*arrIOut=0;
2103       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2104                                                 arrOut,arrIOut);
2105       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2106       setConnectivity(arrOut,arrIOut,true);
2107     }
2108 }
2109
2110
2111 /*!
2112  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2113  * this->getMeshDimension(), that bound some cells of \a this mesh.
2114  * The cells of lower dimension to include to the result mesh are selected basing on
2115  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2116  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2117  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2118  * created mesh shares the node coordinates array with \a this mesh.
2119  *  \param [in] begin - the array of node ids.
2120  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2121  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2122  *         array \a begin are added, else cells whose any node is in the
2123  *         array \a begin are added.
2124  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2125  *         to delete this mesh using decrRef() as it is no more needed.
2126  *  \throw If the coordinates array is not set.
2127  *  \throw If the nodal connectivity of cells is not defined.
2128  *  \throw If any node id in \a begin is not valid.
2129  *
2130  *  \if ENABLE_EXAMPLES
2131  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2132  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2133  *  \endif
2134  */
2135 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2136 {
2137   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2138   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2139   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2140   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2141   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2142 }
2143
2144 /*!
2145  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2146  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2147  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2148  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2149  *         by calling zipCoords().
2150  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2151  *         to delete this mesh using decrRef() as it is no more needed.
2152  *  \throw If the coordinates array is not set.
2153  *  \throw If the nodal connectivity of cells is not defined.
2154  *
2155  *  \if ENABLE_EXAMPLES
2156  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2157  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2158  *  \endif
2159  */
2160 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2161 {
2162   DataArrayIdType *desc=DataArrayIdType::New();
2163   DataArrayIdType *descIndx=DataArrayIdType::New();
2164   DataArrayIdType *revDesc=DataArrayIdType::New();
2165   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2166   //
2167   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2168   revDesc->decrRef();
2169   desc->decrRef();
2170   descIndx->decrRef();
2171   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2172   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2173   std::vector<mcIdType> boundaryCells;
2174   for(mcIdType i=0;i<nbOfCells;i++)
2175     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2176       boundaryCells.push_back(i);
2177   revDescIndx->decrRef();
2178   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2179   return ret;
2180 }
2181
2182 /*!
2183  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2184  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2185  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2186  */
2187 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2188 {
2189   checkFullyDefined();
2190   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2191   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2192   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2193   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2194   //
2195   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2196   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2197   //
2198   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2199   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2200   const mcIdType *revDescPtr=revDesc->getConstPointer();
2201   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2202   mcIdType nbOfCells=getNumberOfCells();
2203   std::vector<bool> ret1(nbOfCells,false);
2204   mcIdType sz=0;
2205   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2206     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2207       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2208   //
2209   DataArrayIdType *ret2=DataArrayIdType::New();
2210   ret2->alloc(sz,1);
2211   mcIdType *ret2Ptr=ret2->getPointer();
2212   sz=0;
2213   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2214     if(*it)
2215       *ret2Ptr++=sz;
2216   ret2->setName("BoundaryCells");
2217   return ret2;
2218 }
2219
2220 /*!
2221  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2222  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2223  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2224  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2225  *
2226  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2227  * 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
2228  * equals a cell in \b otherDimM1OnSameCoords.
2229  *
2230  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2231  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2232  *
2233  * \param [in] otherDimM1OnSameCoords other mesh
2234  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2235  * \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
2236  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2237  */
2238 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2239 {
2240   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2241     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2242   checkConnectivityFullyDefined();
2243   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2244   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2245     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2246   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2247   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2248   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2249   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2250   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2251   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2252   DataArrayIdType *idsOtherInConsti=0;
2253   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2254   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2255   if(!b)
2256     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2257   std::set<mcIdType> s1;
2258   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2259     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2260   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2261   s1arr_renum1->sort();
2262   cellIdsRk0=s0arr.retn();
2263   //cellIdsRk1=s_renum1.retn();
2264   cellIdsRk1=s1arr_renum1.retn();
2265 }
2266
2267 /*!
2268  * 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
2269  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2270  *
2271  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2272  */
2273 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2274 {
2275   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2276   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2277   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2278   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2279   //
2280   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2281   revDesc=0; desc=0; descIndx=0;
2282   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2283   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2284   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2285 }
2286
2287 /*!
2288  * Finds nodes lying on the boundary of \a this mesh.
2289  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2290  *          nodes. The caller is to delete this array using decrRef() as it is no
2291  *          more needed.
2292  *  \throw If the coordinates array is not set.
2293  *  \throw If the nodal connectivity of cells is node defined.
2294  *
2295  *  \if ENABLE_EXAMPLES
2296  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2297  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2298  *  \endif
2299  */
2300 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2301 {
2302   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2303   return skin->computeFetchedNodeIds();
2304 }
2305
2306 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2307 {
2308   incrRef();
2309   return const_cast<MEDCouplingUMesh *>(this);
2310 }
2311
2312 /*!
2313  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2314  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2315  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2316  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2317  * 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.
2318  *
2319  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2320  *             parameter is altered during the call.
2321  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2322  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2323  * \param [out] cellIdsNotModified cell ids mcIdType \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.
2324  *
2325  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2326  */
2327 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2328                                             DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2329 {
2330   typedef MCAuto<DataArrayIdType> DAInt;
2331   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2332
2333   checkFullyDefined();
2334   otherDimM1OnSameCoords.checkFullyDefined();
2335   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2336     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2337   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2338     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2339
2340   // Checking star-shaped M1 group:
2341   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2342   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2343   DAInt dsi = rdit0->deltaShiftIndex();
2344   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2345   if(idsTmp0->getNumberOfTuples())
2346     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2347   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2348
2349   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2350   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2351   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2352   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2353   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2354   dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2355   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2356   dsi = rdit0->deltaShiftIndex();
2357   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2358   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2359   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2360   // In 3D, some points on the boundary of M0 still need duplication:
2361   DAInt notDup = 0;
2362   if (getMeshDimension() == 3)
2363     {
2364       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2365       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2366       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2367       DataArrayIdType * corresp=0;
2368       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2369       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2370       corresp->decrRef();
2371       if (validIds->getNumberOfTuples())
2372         {
2373           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2374           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2375           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2376           notDup = xtrem->buildSubstraction(fNodes1);
2377         }
2378       else
2379         notDup = xtrem->buildSubstraction(fNodes);
2380     }
2381   else
2382     notDup = xtrem->buildSubstraction(fNodes);
2383
2384   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2385   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2386   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2387   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2388
2389   //
2390   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2391   mcIdType nCells2 = m0Part2->getNumberOfCells();
2392   DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2393   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2394
2395   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2396   DataArrayIdType *tmp00=0,*tmp11=0;
2397   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2398   DAInt neighInit00(tmp00);
2399   DAInt neighIInit00(tmp11);
2400   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2401   DataArrayIdType *idsTmp=0;
2402   m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2403   DAInt ids(idsTmp);
2404   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2405   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2406   DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2407   DataArrayIdType *tmp0=0,*tmp1=0;
2408   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2409   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2410   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2411   DAInt neigh00(tmp0);
2412   DAInt neighI00(tmp1);
2413
2414   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2415   mcIdType seed = 0, nIter = 0;
2416   mcIdType nIterMax = nCells2+1; // Safety net for the loop
2417   DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2418   hitCells->fillWithValue(-1);
2419   DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2420   cellsToModifyConn0_torenum->alloc(0,1);
2421   while (nIter < nIterMax)
2422     {
2423       DAInt t = hitCells->findIdsEqual(-1);
2424       if (!t->getNumberOfTuples())
2425         break;
2426       // Connex zone without the crack (to compute the next seed really)
2427       mcIdType dnu;
2428       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2429       mcIdType cnt(0);
2430       for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2431         hitCells->setIJ(*ptr,0,1);
2432       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2433       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2434       cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2435       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2436       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2437       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2438       DAInt intersec = nonHitCells->buildIntersection(comple);
2439       if (intersec->getNumberOfTuples())
2440         { seed = intersec->getIJ(0,0); }
2441       else
2442         { break; }
2443       nIter++;
2444     }
2445   if (nIter >= nIterMax)
2446     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2447
2448   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2449   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2450   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2451   //
2452   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2453   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2454   nodeIdsToDuplicate=dupl.retn();
2455 }
2456
2457 /*!
2458  * This method operates a modification of the connectivity and coords in \b this.
2459  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2460  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2461  * 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
2462  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2463  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2464  *
2465  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2466  *
2467  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2468  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2469  */
2470 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2471 {
2472   mcIdType nbOfNodes=getNumberOfNodes();
2473   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2474   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2475 }
2476
2477 /*!
2478  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2479  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2480  *
2481  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2482  *
2483  * \sa renumberNodesInConn
2484  */
2485 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2486 {
2487   checkConnectivityFullyDefined();
2488   mcIdType *conn(getNodalConnectivity()->getPointer());
2489   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2490   mcIdType nbOfCells=getNumberOfCells();
2491   for(mcIdType i=0;i<nbOfCells;i++)
2492     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2493       {
2494         mcIdType& node=conn[iconn];
2495         if(node>=0)//avoid polyhedron separator
2496           {
2497             node+=offset;
2498           }
2499       }
2500   _nodal_connec->declareAsNew();
2501   updateTime();
2502 }
2503
2504 /*!
2505  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2506  *  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
2507  *  of a big mesh.
2508  */
2509 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2510 {
2511   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2512 }
2513
2514 /*!
2515  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2516  *  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
2517  *  of a big mesh.
2518  */
2519 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2520 {
2521   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2522 }
2523
2524 /*!
2525  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2526  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2527  * This method is a generalization of shiftNodeNumbersInConn().
2528  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2529  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2530  *         this->getNumberOfNodes(), in "Old to New" mode.
2531  *         See \ref numbering for more info on renumbering modes.
2532  *  \throw If the nodal connectivity of cells is not defined.
2533  *
2534  *  \if ENABLE_EXAMPLES
2535  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2536  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2537  *  \endif
2538  */
2539 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2540 {
2541   checkConnectivityFullyDefined();
2542   mcIdType *conn=getNodalConnectivity()->getPointer();
2543   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2544   mcIdType nbOfCells=getNumberOfCells();
2545   for(mcIdType i=0;i<nbOfCells;i++)
2546     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2547       {
2548         mcIdType& node=conn[iconn];
2549         if(node>=0)//avoid polyhedron separator
2550           {
2551             node=newNodeNumbersO2N[node];
2552           }
2553       }
2554   _nodal_connec->declareAsNew();
2555   updateTime();
2556 }
2557
2558 /*!
2559  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2560  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2561  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2562  *
2563  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2564  */
2565 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2566 {
2567   checkConnectivityFullyDefined();
2568   mcIdType *conn=getNodalConnectivity()->getPointer();
2569   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2570   mcIdType nbOfCells=getNumberOfCells();
2571   for(mcIdType i=0;i<nbOfCells;i++)
2572     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2573       {
2574         mcIdType& node=conn[iconn];
2575         if(node>=0)//avoid polyhedron separator
2576           {
2577             node+=delta;
2578           }
2579       }
2580   _nodal_connec->declareAsNew();
2581   updateTime();
2582 }
2583
2584 /*!
2585  * This method operates a modification of the connectivity in \b this.
2586  * 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.
2587  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2588  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2589  * 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
2590  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2591  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2592  *
2593  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2594  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2595  *
2596  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2597  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2598  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2599  */
2600 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2601 {
2602   checkConnectivityFullyDefined();
2603   std::map<mcIdType,mcIdType> m;
2604   mcIdType val=offset;
2605   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2606     m[*work]=val;
2607   mcIdType *conn=getNodalConnectivity()->getPointer();
2608   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2609   mcIdType nbOfCells=getNumberOfCells();
2610   for(mcIdType i=0;i<nbOfCells;i++)
2611     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2612       {
2613         mcIdType& node=conn[iconn];
2614         if(node>=0)//avoid polyhedron separator
2615           {
2616             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2617             if(it!=m.end())
2618               node=(*it).second;
2619           }
2620       }
2621   updateTime();
2622 }
2623
2624 /*!
2625  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2626  *
2627  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2628  * After the call of this method the number of cells remains the same as before.
2629  *
2630  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2631  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2632  * be strictly in [0;this->getNumberOfCells()).
2633  *
2634  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2635  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2636  * should be contained in[0;this->getNumberOfCells()).
2637  *
2638  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2639  * \param check whether to check content of old2NewBg
2640  */
2641 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2642 {
2643   checkConnectivityFullyDefined();
2644   mcIdType nbCells=getNumberOfCells();
2645   const mcIdType *array=old2NewBg;
2646   if(check)
2647     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2648   //
2649   const mcIdType *conn=_nodal_connec->getConstPointer();
2650   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2651   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2652   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2653   const mcIdType *n2oPtr=n2o->begin();
2654   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2655   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2656   newConn->copyStringInfoFrom(*_nodal_connec);
2657   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2658   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2659   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2660   //
2661   mcIdType *newC=newConn->getPointer();
2662   mcIdType *newCI=newConnI->getPointer();
2663   mcIdType loc=0;
2664   newCI[0]=loc;
2665   for(mcIdType i=0;i<nbCells;i++)
2666     {
2667       mcIdType pos=n2oPtr[i];
2668       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2669       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2670       loc+=nbOfElts;
2671       newCI[i+1]=loc;
2672     }
2673   //
2674   setConnectivity(newConn,newConnI);
2675   if(check)
2676     free(const_cast<mcIdType *>(array));
2677 }
2678
2679 /*!
2680  * Finds cells whose bounding boxes intersect a given bounding box.
2681  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2682  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2683  *         zMax (if in 3D).
2684  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2685  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2686  *         extent of the bounding box of cell to produce an addition to this bounding box.
2687  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2688  *         cells. The caller is to delete this array using decrRef() as it is no more
2689  *         needed.
2690  *  \throw If the coordinates array is not set.
2691  *  \throw If the nodal connectivity of cells is not defined.
2692  *
2693  *  \if ENABLE_EXAMPLES
2694  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2695  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2696  *  \endif
2697  */
2698 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2699 {
2700   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2701   if(getMeshDimension()==-1)
2702     {
2703       elems->pushBackSilent(0);
2704       return elems.retn();
2705     }
2706   int dim=getSpaceDimension();
2707   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2708   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2709   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2710   const double* coords = getCoords()->getConstPointer();
2711   mcIdType nbOfCells=getNumberOfCells();
2712   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2713     {
2714       for (int i=0; i<dim; i++)
2715         {
2716           elem_bb[i*2]=std::numeric_limits<double>::max();
2717           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2718         }
2719
2720       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2721         {
2722           mcIdType node= conn[inode];
2723           if(node>=0)//avoid polyhedron separator
2724             {
2725               for (int idim=0; idim<dim; idim++)
2726                 {
2727                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2728                     {
2729                       elem_bb[idim*2] = coords[node*dim+idim] ;
2730                     }
2731                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2732                     {
2733                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2734                     }
2735                 }
2736             }
2737         }
2738       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2739         elems->pushBackSilent(ielem);
2740     }
2741   return elems.retn();
2742 }
2743
2744 /*!
2745  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2746  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2747  * added in 'elems' parameter.
2748  */
2749 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2750 {
2751   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2752   if(getMeshDimension()==-1)
2753     {
2754       elems->pushBackSilent(0);
2755       return elems.retn();
2756     }
2757   int dim=getSpaceDimension();
2758   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2759   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2760   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2761   const double* coords = getCoords()->getConstPointer();
2762   mcIdType nbOfCells=getNumberOfCells();
2763   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2764     {
2765       for (int i=0; i<dim; i++)
2766         {
2767           elem_bb[i*2]=std::numeric_limits<double>::max();
2768           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2769         }
2770
2771       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2772         {
2773           mcIdType node= conn[inode];
2774           if(node>=0)//avoid polyhedron separator
2775             {
2776               for (int idim=0; idim<dim; idim++)
2777                 {
2778                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2779                     {
2780                       elem_bb[idim*2] = coords[node*dim+idim] ;
2781                     }
2782                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2783                     {
2784                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2785                     }
2786                 }
2787             }
2788         }
2789       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2790         elems->pushBackSilent(ielem);
2791     }
2792   return elems.retn();
2793 }
2794
2795 /*!
2796  * Returns a type of a cell by its id.
2797  *  \param [in] cellId - the id of the cell of interest.
2798  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2799  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2800  */
2801 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2802 {
2803   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2804   if(cellId<_nodal_connec_index->getNbOfElems()-1)
2805     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2806   else
2807     {
2808       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2809       throw INTERP_KERNEL::Exception(oss.str());
2810     }
2811 }
2812
2813 /*!
2814  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2815  * This method does not throw exception if geometric type \a type is not in \a this.
2816  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2817  * The coordinates array is not considered here.
2818  *
2819  * \param [in] type the geometric type
2820  * \return cell ids in this having geometric type \a type.
2821  */
2822 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2823 {
2824
2825   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2826   ret->alloc(0,1);
2827   checkConnectivityFullyDefined();
2828   mcIdType nbCells=getNumberOfCells();
2829   int mdim=getMeshDimension();
2830   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2831   if(mdim!=ToIdType(cm.getDimension()))
2832     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2833   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2834   const mcIdType *pt=_nodal_connec->getConstPointer();
2835   for(mcIdType i=0;i<nbCells;i++)
2836     {
2837       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2838         ret->pushBackSilent(i);
2839     }
2840   return ret.retn();
2841 }
2842
2843 /*!
2844  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2845  */
2846 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2847 {
2848   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2849   mcIdType nbOfCells(getNumberOfCells()),ret(0);
2850   for(mcIdType i=0;i<nbOfCells;i++)
2851     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2852       ret++;
2853   return ret;
2854 }
2855
2856 /*!
2857  * Returns the nodal connectivity of a given cell.
2858  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2859  * all returned node ids can be used in getCoordinatesOfNode().
2860  *  \param [in] cellId - an id of the cell of interest.
2861  *  \param [in,out] conn - a vector where the node ids are appended. It is not
2862  *         cleared before the appending.
2863  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2864  */
2865 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2866 {
2867   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2868   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2869     if(*w>=0)
2870       conn.push_back(*w);
2871 }
2872
2873 std::string MEDCouplingUMesh::simpleRepr() const
2874 {
2875   static const char msg0[]="No coordinates specified !";
2876   std::ostringstream ret;
2877   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2878   ret << "Description of mesh : \"" << getDescription() << "\"\n";
2879   int tmpp1,tmpp2;
2880   double tt=getTime(tmpp1,tmpp2);
2881   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2882   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
2883   if(_mesh_dim>=-1)
2884     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2885   else
2886     { ret << " Mesh dimension has not been set or is invalid !"; }
2887   if(_coords!=0)
2888     {
2889       const int spaceDim=getSpaceDimension();
2890       ret << spaceDim << "\nInfo attached on space dimension : ";
2891       for(int i=0;i<spaceDim;i++)
2892         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2893       ret << "\n";
2894     }
2895   else
2896     ret << msg0 << "\n";
2897   ret << "Number of nodes : ";
2898   if(_coords!=0)
2899     ret << getNumberOfNodes() << "\n";
2900   else
2901     ret << msg0 << "\n";
2902   ret << "Number of cells : ";
2903   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2904     ret << getNumberOfCells() << "\n";
2905   else
2906     ret << "No connectivity specified !" << "\n";
2907   ret << "Cell types present : ";
2908   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2909     {
2910       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2911       ret << cm.getRepr() << " ";
2912     }
2913   ret << "\n";
2914   return ret.str();
2915 }
2916
2917 std::string MEDCouplingUMesh::advancedRepr() const
2918 {
2919   std::ostringstream ret;
2920   ret << simpleRepr();
2921   ret << "\nCoordinates array : \n___________________\n\n";
2922   if(_coords)
2923     _coords->reprWithoutNameStream(ret);
2924   else
2925     ret << "No array set !\n";
2926   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2927   reprConnectivityOfThisLL(ret);
2928   return ret.str();
2929 }
2930
2931 /*!
2932  * This method returns a C++ code that is a dump of \a this.
2933  * This method will throw if this is not fully defined.
2934  */
2935 std::string MEDCouplingUMesh::cppRepr() const
2936 {
2937   static const char coordsName[]="coords";
2938   static const char connName[]="conn";
2939   static const char connIName[]="connI";
2940   checkFullyDefined();
2941   std::ostringstream ret; ret << "// coordinates" << std::endl;
2942   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2943   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2944   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2945   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2946   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2947   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2948   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2949   return ret.str();
2950 }
2951
2952 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2953 {
2954   std::ostringstream ret;
2955   reprConnectivityOfThisLL(ret);
2956   return ret.str();
2957 }
2958
2959 /*!
2960  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2961  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2962  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2963  * some algos).
2964  *
2965  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2966  * 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
2967  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2968  */
2969 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2970 {
2971   int mdim=getMeshDimension();
2972   if(mdim<0)
2973     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2974   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2975   MCAuto<DataArrayIdType> tmp1,tmp2;
2976   bool needToCpyCT=true;
2977   if(!_nodal_connec)
2978     {
2979       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2980       needToCpyCT=false;
2981     }
2982   else
2983     {
2984       tmp1=_nodal_connec;
2985       tmp1->incrRef();
2986     }
2987   if(!_nodal_connec_index)
2988     {
2989       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2990       needToCpyCT=false;
2991     }
2992   else
2993     {
2994       tmp2=_nodal_connec_index;
2995       tmp2->incrRef();
2996     }
2997   ret->setConnectivity(tmp1,tmp2,false);
2998   if(needToCpyCT)
2999     ret->_types=_types;
3000   if(!_coords)
3001     {
3002       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3003       ret->setCoords(coords);
3004     }
3005   else
3006     ret->setCoords(_coords);
3007   return ret.retn();
3008 }
3009
3010 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3011 {
3012   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3013   const mcIdType *pt=_nodal_connec->getConstPointer();
3014   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3015     return ptI[cellId+1]-ptI[cellId]-1;
3016   else
3017     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3018 }
3019
3020 /*!
3021  * Returns types of cells of the specified part of \a this mesh.
3022  * This method avoids computing sub-mesh explicitly to get its types.
3023  *  \param [in] begin - an array of cell ids of interest.
3024  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3025  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3026  *         describing the cell types.
3027  *  \throw If the coordinates array is not set.
3028  *  \throw If the nodal connectivity of cells is not defined.
3029  *  \sa getAllGeoTypes()
3030  */
3031 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3032 {
3033   checkFullyDefined();
3034   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3035   const mcIdType *conn=_nodal_connec->getConstPointer();
3036   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3037   for(const mcIdType *w=begin;w!=end;w++)
3038     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3039   return ret;
3040 }
3041
3042 /*!
3043  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3044  * Optionally updates
3045  * a set of types of cells constituting \a this mesh.
3046  * This method is for advanced users having prepared their connectivity before. For
3047  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3048  *  \param [in] conn - the nodal connectivity array.
3049  *  \param [in] connIndex - the nodal connectivity index array.
3050  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3051  *         mesh is updated.
3052  */
3053 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3054 {
3055   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3056   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3057   if(isComputingTypes)
3058     computeTypes();
3059   declareAsNew();
3060 }
3061
3062 /*!
3063  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3064  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3065  */
3066 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3067     _nodal_connec(0),_nodal_connec_index(0),
3068     _types(other._types)
3069 {
3070   if(other._nodal_connec)
3071     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3072   if(other._nodal_connec_index)
3073     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3074 }
3075
3076 MEDCouplingUMesh::~MEDCouplingUMesh()
3077 {
3078   if(_nodal_connec)
3079     _nodal_connec->decrRef();
3080   if(_nodal_connec_index)
3081     _nodal_connec_index->decrRef();
3082 }
3083
3084 /*!
3085  * Recomputes a set of cell types of \a this mesh. For more info see
3086  * \ref MEDCouplingUMeshNodalConnectivity.
3087  */
3088 void MEDCouplingUMesh::computeTypes()
3089 {
3090   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3091 }
3092
3093
3094 /*!
3095  * Returns a number of cells constituting \a this mesh.
3096  *  \return mcIdType - the number of cells in \a this mesh.
3097  *  \throw If the nodal connectivity of cells is not defined.
3098  */
3099 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3100 {
3101   if(_nodal_connec_index)
3102     return _nodal_connec_index->getNumberOfTuples()-1;
3103   else
3104     if(_mesh_dim==-1)
3105       return 1;
3106     else
3107       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3108 }
3109
3110 /*!
3111  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3112  * mesh. For more info see \ref meshes.
3113  *  \return int - the dimension of \a this mesh.
3114  *  \throw If the mesh dimension is not defined using setMeshDimension().
3115  */
3116 int MEDCouplingUMesh::getMeshDimension() const
3117 {
3118   if(_mesh_dim<-1)
3119     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3120   return _mesh_dim;
3121 }
3122
3123 /*!
3124  * Returns a length of the nodal connectivity array.
3125  * This method is for test reason. Normally the integer returned is not useable by
3126  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3127  *  \return mcIdType - the length of the nodal connectivity array.
3128  */
3129 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3130 {
3131   return _nodal_connec->getNbOfElems();
3132 }
3133
3134 /*!
3135  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3136  */
3137 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3138 {
3139   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3140   tinyInfo.push_back(ToIdType(getMeshDimension()));
3141   tinyInfo.push_back(getNumberOfCells());
3142   if(_nodal_connec)
3143     tinyInfo.push_back(getNodalConnectivityArrayLen());
3144   else
3145     tinyInfo.push_back(-1);
3146 }
3147
3148 /*!
3149  * First step of unserialization process.
3150  */
3151 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3152 {
3153   return tinyInfo[6]<=0;
3154 }
3155
3156 /*!
3157  * Second step of serialization process.
3158  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3159  * \param a1 DataArrayDouble
3160  * \param a2 DataArrayDouble
3161  * \param littleStrings string vector
3162  */
3163 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3164 {
3165   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3166   if(tinyInfo[5]!=-1)
3167     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3168 }
3169
3170 /*!
3171  * Third and final step of serialization process.
3172  */
3173 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3174 {
3175   MEDCouplingPointSet::serialize(a1,a2);
3176   if(getMeshDimension()>-1)
3177     {
3178       a1=DataArrayIdType::New();
3179       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3180       mcIdType *ptA1=a1->getPointer();
3181       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3182       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3183       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3184       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3185     }
3186   else
3187     a1=0;
3188 }
3189
3190 /*!
3191  * Second and final unserialization process.
3192  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3193  */
3194 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3195 {
3196   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3197   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3198   if(tinyInfo[7]!=-1)
3199     {
3200       // Connectivity
3201       const mcIdType *recvBuffer=a1->getConstPointer();
3202       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3203       myConnecIndex->alloc(tinyInfo[6]+1,1);
3204       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3205       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3206       myConnec->alloc(tinyInfo[7],1);
3207       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3208       setConnectivity(myConnec, myConnecIndex);
3209     }
3210 }
3211
3212
3213
3214 /*!
3215  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3216  * mesh.<br>
3217  * For 1D cells, the returned field contains lengths.<br>
3218  * For 2D cells, the returned field contains areas.<br>
3219  * For 3D cells, the returned field contains volumes.
3220  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3221  *         orientation, i.e. the volume is always positive.
3222  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3223  *         and one time . The caller is to delete this field using decrRef() as it is no
3224  *         more needed.
3225  */
3226 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3227 {
3228   std::string name="MeasureOfMesh_";
3229   name+=getName();
3230   mcIdType nbelem=getNumberOfCells();
3231   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3232   field->setName(name);
3233   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3234   array->alloc(nbelem,1);
3235   double *area_vol=array->getPointer();
3236   field->setArray(array) ; array=0;
3237   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3238   field->synchronizeTimeWithMesh();
3239   if(getMeshDimension()!=-1)
3240     {
3241       mcIdType ipt;
3242       INTERP_KERNEL::NormalizedCellType type;
3243       int dim_space=getSpaceDimension();
3244       const double *coords=getCoords()->getConstPointer();
3245       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3246       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3247       for(mcIdType iel=0;iel<nbelem;iel++)
3248         {
3249           ipt=connec_index[iel];
3250           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3251           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);
3252         }
3253       if(isAbs)
3254         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3255     }
3256   else
3257     {
3258       area_vol[0]=std::numeric_limits<double>::max();
3259     }
3260   return field.retn();
3261 }
3262
3263 /*!
3264  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3265  * mesh.<br>
3266  * For 1D cells, the returned array contains lengths.<br>
3267  * For 2D cells, the returned array contains areas.<br>
3268  * For 3D cells, the returned array contains volumes.
3269  * This method avoids building explicitly a part of \a this mesh to perform the work.
3270  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3271  *         orientation, i.e. the volume is always positive.
3272  *  \param [in] begin - an array of cell ids of interest.
3273  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3274  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3275  *          delete this array using decrRef() as it is no more needed.
3276  *
3277  *  \if ENABLE_EXAMPLES
3278  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3279  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3280  *  \endif
3281  *  \sa getMeasureField()
3282  */
3283 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3284 {
3285   std::string name="PartMeasureOfMesh_";
3286   name+=getName();
3287   std::size_t nbelem=std::distance(begin,end);
3288   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3289   array->setName(name);
3290   array->alloc(nbelem,1);
3291   double *area_vol=array->getPointer();
3292   if(getMeshDimension()!=-1)
3293     {
3294       mcIdType ipt;
3295       INTERP_KERNEL::NormalizedCellType type;
3296       int dim_space=getSpaceDimension();
3297       const double *coords=getCoords()->getConstPointer();
3298       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3299       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3300       for(const mcIdType *iel=begin;iel!=end;iel++)
3301         {
3302           ipt=connec_index[*iel];
3303           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3304           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3305         }
3306       if(isAbs)
3307         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3308     }
3309   else
3310     {
3311       area_vol[0]=std::numeric_limits<double>::max();
3312     }
3313   return array.retn();
3314 }
3315
3316 /*!
3317  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3318  * \a this one. The returned field contains the dual cell volume for each corresponding
3319  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3320  *  the dual mesh in P1 sens of \a this.<br>
3321  * For 1D cells, the returned field contains lengths.<br>
3322  * For 2D cells, the returned field contains areas.<br>
3323  * For 3D cells, the returned field contains volumes.
3324  * This method is useful to check "P1*" conservative interpolators.
3325  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3326  *         orientation, i.e. the volume is always positive.
3327  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3328  *          nodes and one time. The caller is to delete this array using decrRef() as
3329  *          it is no more needed.
3330  */
3331 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3332 {
3333   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3334   std::string name="MeasureOnNodeOfMesh_";
3335   name+=getName();
3336   mcIdType nbNodes=getNumberOfNodes();
3337   MCAuto<DataArrayDouble> nnpc;
3338   {
3339     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3340     nnpc=tmp2->convertToDblArr();
3341   }
3342   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3343   const double *nnpcPtr(nnpc->begin());
3344   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3345   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3346   array->alloc(nbNodes,1);
3347   double *valsToFill=array->getPointer();
3348   std::fill(valsToFill,valsToFill+nbNodes,0.);
3349   const double *values=tmp->getArray()->getConstPointer();
3350   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3351   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3352   getReverseNodalConnectivity(da,daInd);
3353   const mcIdType *daPtr=da->getConstPointer();
3354   const mcIdType *daIPtr=daInd->getConstPointer();
3355   for(mcIdType i=0;i<nbNodes;i++)
3356     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3357       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3358   ret->setMesh(this);
3359   ret->setArray(array);
3360   return ret.retn();
3361 }
3362
3363 /*!
3364  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3365  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3366  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3367  * and are normalized.
3368  * <br> \a this can be either
3369  * - a  2D mesh in 2D or 3D space or
3370  * - an 1D mesh in 2D space.
3371  *
3372  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3373  *          cells and one time. The caller is to delete this field using decrRef() as
3374  *          it is no more needed.
3375  *  \throw If the nodal connectivity of cells is not defined.
3376  *  \throw If the coordinates array is not set.
3377  *  \throw If the mesh dimension is not set.
3378  *  \throw If the mesh and space dimension is not as specified above.
3379  */
3380 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3381 {
3382   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3383     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3384   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3385   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3386   mcIdType nbOfCells=getNumberOfCells();
3387   int nbComp=getMeshDimension()+1;
3388   array->alloc(nbOfCells,nbComp);
3389   double *vals=array->getPointer();
3390   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3391   const mcIdType *conn=_nodal_connec->getConstPointer();
3392   const double *coords=_coords->getConstPointer();
3393   if(getMeshDimension()==2)
3394     {
3395       if(getSpaceDimension()==3)
3396         {
3397           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3398           const double *locPtr=loc->getConstPointer();
3399           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3400             {
3401               mcIdType offset=connI[i];
3402               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3403               double n=INTERP_KERNEL::norm<3>(vals);
3404               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3405             }
3406         }
3407       else
3408         {
3409           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3410           const double *isAbsPtr=isAbs->getArray()->begin();
3411           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3412             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3413         }
3414     }
3415   else//meshdimension==1
3416     {
3417       double tmp[2];
3418       for(mcIdType i=0;i<nbOfCells;i++)
3419         {
3420           mcIdType offset=connI[i];
3421           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3422           double n=INTERP_KERNEL::norm<2>(tmp);
3423           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3424           *vals++=-tmp[1];
3425           *vals++=tmp[0];
3426         }
3427     }
3428   ret->setArray(array);
3429   ret->setMesh(this);
3430   ret->synchronizeTimeWithSupport();
3431   return ret.retn();
3432 }
3433
3434 /*!
3435  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3436  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3437  * and are normalized.
3438  * <br> \a this can be either
3439  * - a  2D mesh in 2D or 3D space or
3440  * - an 1D mesh in 2D space.
3441  *
3442  * This method avoids building explicitly a part of \a this mesh to perform the work.
3443  *  \param [in] begin - an array of cell ids of interest.
3444  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3445  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3446  *          cells and one time. The caller is to delete this field using decrRef() as
3447  *          it is no more needed.
3448  *  \throw If the nodal connectivity of cells is not defined.
3449  *  \throw If the coordinates array is not set.
3450  *  \throw If the mesh dimension is not set.
3451  *  \throw If the mesh and space dimension is not as specified above.
3452  *  \sa buildOrthogonalField()
3453  *
3454  *  \if ENABLE_EXAMPLES
3455  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3456  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3457  *  \endif
3458  */
3459 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3460 {
3461   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3462     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3463   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3464   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3465   std::size_t nbelems=std::distance(begin,end);
3466   int nbComp=getMeshDimension()+1;
3467   array->alloc(nbelems,nbComp);
3468   double *vals=array->getPointer();
3469   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3470   const mcIdType *conn=_nodal_connec->getConstPointer();
3471   const double *coords=_coords->getConstPointer();
3472   if(getMeshDimension()==2)
3473     {
3474       if(getSpaceDimension()==3)
3475         {
3476           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3477           const double *locPtr=loc->getConstPointer();
3478           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3479             {
3480               mcIdType offset=connI[*i];
3481               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3482               double n=INTERP_KERNEL::norm<3>(vals);
3483               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3484             }
3485         }
3486       else
3487         {
3488           for(std::size_t i=0;i<nbelems;i++)
3489             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3490         }
3491     }
3492   else//meshdimension==1
3493     {
3494       double tmp[2];
3495       for(const mcIdType *i=begin;i!=end;i++)
3496         {
3497           mcIdType offset=connI[*i];
3498           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3499           double n=INTERP_KERNEL::norm<2>(tmp);
3500           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3501           *vals++=-tmp[1];
3502           *vals++=tmp[0];
3503         }
3504     }
3505   ret->setArray(array);
3506   ret->setMesh(this);
3507   ret->synchronizeTimeWithSupport();
3508   return ret.retn();
3509 }
3510
3511 /*!
3512  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3513  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3514  * and are \b not normalized.
3515  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3516  *          cells and one time. The caller is to delete this field using decrRef() as
3517  *          it is no more needed.
3518  *  \throw If the nodal connectivity of cells is not defined.
3519  *  \throw If the coordinates array is not set.
3520  *  \throw If \a this->getMeshDimension() != 1.
3521  *  \throw If \a this mesh includes cells of type other than SEG2.
3522  */
3523 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3524 {
3525   if(getMeshDimension()!=1)
3526     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3527   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3528     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3529   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3530   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3531   mcIdType nbOfCells=getNumberOfCells();
3532   int spaceDim=getSpaceDimension();
3533   array->alloc(nbOfCells,spaceDim);
3534   double *pt=array->getPointer();
3535   const double *coo=getCoords()->getConstPointer();
3536   std::vector<mcIdType> conn;
3537   conn.reserve(2);
3538   for(mcIdType i=0;i<nbOfCells;i++)
3539     {
3540       conn.resize(0);
3541       getNodeIdsOfCell(i,conn);
3542       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3543     }
3544   ret->setArray(array);
3545   ret->setMesh(this);
3546   ret->synchronizeTimeWithSupport();
3547   return ret.retn();
3548 }
3549
3550 /*!
3551  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3552  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3553  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3554  * from. If a result face is shared by two 3D cells, then the face in included twice in
3555  * the result mesh.
3556  *  \param [in] origin - 3 components of a point defining location of the plane.
3557  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3558  *         must be greater than 1e-6.
3559  *  \param [in] eps - half-thickness of the plane.
3560  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3561  *         producing correspondent 2D cells. The caller is to delete this array
3562  *         using decrRef() as it is no more needed.
3563  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3564  *         not share the node coordinates array with \a this mesh. The caller is to
3565  *         delete this mesh using decrRef() as it is no more needed.
3566  *  \throw If the coordinates array is not set.
3567  *  \throw If the nodal connectivity of cells is not defined.
3568  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3569  *  \throw If magnitude of \a vec is less than 1e-6.
3570  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3571  *  \throw If \a this includes quadratic cells.
3572  */
3573 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3574 {
3575   checkFullyDefined();
3576   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3577     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3578   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3579   if(candidates->empty())
3580     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3581   std::vector<mcIdType> nodes;
3582   DataArrayIdType *cellIds1D=0;
3583   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3584   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3585   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3586   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3587   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3588   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3589   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3590   revDesc2=0; revDescIndx2=0;
3591   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3592   revDesc1=0; revDescIndx1=0;
3593   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3594   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3595   //
3596   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3597   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3598     cut3DCurve[*it]=-1;
3599   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3600   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3601   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3602                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3603                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3604   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3605   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3606   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3607   if(cellIds2->empty())
3608     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3609   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3610   ret->setCoords(mDesc1->getCoords());
3611   ret->setConnectivity(conn,connI,true);
3612   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3613   return ret.retn();
3614 }
3615
3616 /*!
3617  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3618 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
3619 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3620 the result mesh.
3621  *  \param [in] origin - 3 components of a point defining location of the plane.
3622  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3623  *         must be greater than 1e-6.
3624  *  \param [in] eps - half-thickness of the plane.
3625  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3626  *         producing correspondent segments. The caller is to delete this array
3627  *         using decrRef() as it is no more needed.
3628  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3629  *         mesh in 3D space. This mesh does not share the node coordinates array with
3630  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3631  *         no more needed.
3632  *  \throw If the coordinates array is not set.
3633  *  \throw If the nodal connectivity of cells is not defined.
3634  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3635  *  \throw If magnitude of \a vec is less than 1e-6.
3636  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3637  *  \throw If \a this includes quadratic cells.
3638  */
3639 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3640 {
3641   checkFullyDefined();
3642   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3643     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3644   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3645   if(candidates->empty())
3646     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3647   std::vector<mcIdType> nodes;
3648   DataArrayIdType *cellIds1D(0);
3649   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3650   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3651   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3652   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3653   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3654   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3655   //
3656   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3657   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3658     cut3DCurve[*it]=-1;
3659   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3660   mcIdType ncellsSub=subMesh->getNumberOfCells();
3661   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3662   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3663                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3664                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3665   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3666   conn->alloc(0,1);
3667   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3668   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3669   for(mcIdType i=0;i<ncellsSub;i++)
3670     {
3671       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3672         {
3673           if(cut3DSurf[i].first!=-2)
3674             {
3675               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3676               connI->pushBackSilent(conn->getNumberOfTuples());
3677               cellIds2->pushBackSilent(i);
3678             }
3679           else
3680             {
3681               mcIdType cellId3DSurf=cut3DSurf[i].second;
3682               mcIdType offset=nodalI[cellId3DSurf]+1;
3683               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3684               for(mcIdType j=0;j<nbOfEdges;j++)
3685                 {
3686                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3687                   connI->pushBackSilent(conn->getNumberOfTuples());
3688                   cellIds2->pushBackSilent(cellId3DSurf);
3689                 }
3690             }
3691         }
3692     }
3693   if(cellIds2->empty())
3694     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3695   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3696   ret->setCoords(mDesc1->getCoords());
3697   ret->setConnectivity(conn,connI,true);
3698   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3699   return ret.retn();
3700 }
3701
3702 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3703 {
3704   checkFullyDefined();
3705   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3706     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3707   if(getNumberOfCells()!=1)
3708     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3709   //
3710   std::vector<mcIdType> nodes;
3711   findNodesOnPlane(origin,vec,eps,nodes);
3712   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());
3713   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3714   revDesc2=0; revDescIndx2=0;
3715   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3716   revDesc1=0; revDescIndx1=0;
3717   DataArrayIdType *cellIds1D(0);
3718   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3719   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3720   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3721   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3722     cut3DCurve[*it]=-1;
3723   bool sameNbNodes;
3724   {
3725     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3726     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3727     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3728   }
3729   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3730   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3731                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3732                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3733   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3734   connI->pushBackSilent(0); conn->alloc(0,1);
3735   {
3736     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3737     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3738     if(cellIds2->empty())
3739       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3740   }
3741   std::vector<std::vector<mcIdType> > res;
3742   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3743   std::size_t sz(res.size());
3744   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3745     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3746   for(std::size_t i=0;i<sz;i++)
3747     {
3748       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3749       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3750       connI->pushBackSilent(conn->getNumberOfTuples());
3751     }
3752   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3753   ret->setCoords(mDesc1->getCoords());
3754   ret->setConnectivity(conn,connI,true);
3755   mcIdType nbCellsRet(ret->getNumberOfCells());
3756   //
3757   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3758   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3759   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3760   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3761   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3762   MCAuto<DataArrayDouble> occm;
3763   {
3764     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3765     occm=DataArrayDouble::Substract(ccm,pt);
3766   }
3767   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3768   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);
3769   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3770   //
3771   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3772   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3773   ret2->setCoords(mDesc1->getCoords());
3774   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3775   conn2I->pushBackSilent(0); conn2->alloc(0,1);
3776   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3777   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3778   if(dott->getIJ(0,0)>0)
3779     {
3780       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3781       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3782     }
3783   else
3784     {
3785       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3786       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3787     }
3788   for(mcIdType i=1;i<nbCellsRet;i++)
3789     {
3790       if(dott2->getIJ(i,0)<0)
3791         {
3792           if(ciPtr[i+1]-ciPtr[i]>=4)
3793             {
3794               cell0.push_back(-1);
3795               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3796             }
3797         }
3798       else
3799         {
3800           if(ciPtr[i+1]-ciPtr[i]>=4)
3801             {
3802               cell1.push_back(-1);
3803               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3804             }
3805         }
3806     }
3807   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3808   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3809   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3810   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3811   ret2->setConnectivity(conn2,conn2I,true);
3812   ret2->checkConsistencyLight();
3813   ret2->orientCorrectlyPolyhedrons();
3814   return ret2;
3815 }
3816
3817 /*!
3818  * Finds cells whose bounding boxes intersect a given plane.
3819  *  \param [in] origin - 3 components of a point defining location of the plane.
3820  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3821  *         must be greater than 1e-6.
3822  *  \param [in] eps - half-thickness of the plane.
3823  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3824  *         cells. The caller is to delete this array using decrRef() as it is no more
3825  *         needed.
3826  *  \throw If the coordinates array is not set.
3827  *  \throw If the nodal connectivity of cells is not defined.
3828  *  \throw If \a this->getSpaceDimension() != 3.
3829  *  \throw If magnitude of \a vec is less than 1e-6.
3830  *  \sa buildSlice3D()
3831  */
3832 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3833 {
3834   checkFullyDefined();
3835   if(getSpaceDimension()!=3)
3836     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3837   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3838   if(normm<1e-6)
3839     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3840   double vec2[3];
3841   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3842   double angle=acos(vec[2]/normm);
3843   MCAuto<DataArrayIdType> cellIds;
3844   double bbox[6];
3845   if(angle>eps)
3846     {
3847       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3848       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3849       if(normm2/normm>1e-6)
3850         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3851       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3852       mw->setCoords(coo);
3853       mw->getBoundingBox(bbox);
3854       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3855       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3856     }
3857   else
3858     {
3859       getBoundingBox(bbox);
3860       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3861       cellIds=getCellsInBoundingBox(bbox,eps);
3862     }
3863   return cellIds.retn();
3864 }
3865
3866 /*!
3867  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3868  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3869  * No consideration of coordinate is done by this method.
3870  * 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)
3871  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3872  */
3873 bool MEDCouplingUMesh::isContiguous1D() const
3874 {
3875   if(getMeshDimension()!=1)
3876     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3877   mcIdType nbCells=getNumberOfCells();
3878   if(nbCells<1)
3879     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3880   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3881   mcIdType ref=conn[connI[0]+2];
3882   for(mcIdType i=1;i<nbCells;i++)
3883     {
3884       if(conn[connI[i]+1]!=ref)
3885         return false;
3886       ref=conn[connI[i]+2];
3887     }
3888   return true;
3889 }
3890
3891 /*!
3892  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3893  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3894  * \param pt reference point of the line
3895  * \param v normalized director vector of the line
3896  * \param eps max precision before throwing an exception
3897  * \param res output of size this->getNumberOfCells
3898  */
3899 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3900 {
3901   if(getMeshDimension()!=1)
3902     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3903   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3904     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3905   if(getSpaceDimension()!=3)
3906     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3907   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3908   const double *fPtr=f->getArray()->getConstPointer();
3909   double tmp[3];
3910   for(mcIdType i=0;i<getNumberOfCells();i++)
3911     {
3912       const double *tmp1=fPtr+3*i;
3913       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3914       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3915       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3916       double n1=INTERP_KERNEL::norm<3>(tmp);
3917       n1/=INTERP_KERNEL::norm<3>(tmp1);
3918       if(n1>eps)
3919         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3920     }
3921   const double *coo=getCoords()->getConstPointer();
3922   for(mcIdType i=0;i<getNumberOfNodes();i++)
3923     {
3924       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3925       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3926       res[i]=std::accumulate(tmp,tmp+3,0.);
3927     }
3928 }
3929
3930 /*!
3931  * 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.
3932  * \a this is expected to be a mesh so that its space dimension is equal to its
3933  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3934  * 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).
3935  *
3936  * 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
3937  * 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).
3938  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3939  *
3940  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3941  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3942  *
3943  * \param [in] ptBg the start pointer (included) of the coordinates of the point
3944  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3945  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3946  * \return the positive value of the distance.
3947  * \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
3948  * dimension - 1.
3949  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3950  */
3951 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3952 {
3953   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3954   if(meshDim!=spaceDim-1)
3955     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3956   if(meshDim!=2 && meshDim!=1)
3957     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3958   checkFullyDefined();
3959   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3960     { 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()); }
3961   DataArrayIdType *ret1=0;
3962   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3963   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3964   MCAuto<DataArrayIdType> ret1Safe(ret1);
3965   cellId=*ret1Safe->begin();
3966   return *ret0->begin();
3967 }
3968
3969 /*!
3970  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3971  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
3972  * 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
3973  * 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).
3974  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3975  *
3976  * \a this is expected to be a mesh so that its space dimension is equal to its
3977  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3978  * 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).
3979  *
3980  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3981  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3982  *
3983  * \param [in] pts the list of points in which each tuple represents a point
3984  * \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.
3985  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3986  * \throw if number of components of \a pts is not equal to the space dimension.
3987  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3988  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3989  */
3990 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3991 {
3992   if(!pts)
3993     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3994   pts->checkAllocated();
3995   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3996   if(meshDim!=spaceDim-1)
3997     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3998   if(meshDim!=2 && meshDim!=1)
3999     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4000   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4001     {
4002       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4003       throw INTERP_KERNEL::Exception(oss.str());
4004     }
4005   checkFullyDefined();
4006   mcIdType nbCells=getNumberOfCells();
4007   if(nbCells==0)
4008     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4009   mcIdType nbOfPts=pts->getNumberOfTuples();
4010   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4011   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4012   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4013   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4014   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4015   const double *bbox(bboxArr->begin());
4016   switch(spaceDim)
4017   {
4018     case 3:
4019       {
4020         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4021         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4022           {
4023             double x=std::numeric_limits<double>::max();
4024             std::vector<mcIdType> elems;
4025             myTree.getMinDistanceOfMax(ptsPtr,x);
4026             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4027             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4028           }
4029         break;
4030       }
4031     case 2:
4032       {
4033         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4034         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4035           {
4036             double x=std::numeric_limits<double>::max();
4037             std::vector<mcIdType> elems;
4038             myTree.getMinDistanceOfMax(ptsPtr,x);
4039             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4040             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4041           }
4042         break;
4043       }
4044     default:
4045       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4046   }
4047   cellIds=ret1.retn();
4048   return ret0.retn();
4049 }
4050
4051 /// @cond INTERNAL
4052
4053 /// @endcond
4054
4055 /*!
4056  * Finds cells in contact with a ball (i.e. a point with precision).
4057  * 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.
4058  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4059  *
4060  * \warning This method is suitable if the caller intends to evaluate only one
4061  *          point, for more points getCellsContainingPoints() is recommended as it is
4062  *          faster.
4063  *  \param [in] pos - array of coordinates of the ball central point.
4064  *  \param [in] eps - ball radius.
4065  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4066  *         if there are no such cells.
4067  *  \throw If the coordinates array is not set.
4068  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4069  */
4070 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4071 {
4072   std::vector<mcIdType> elts;
4073   getCellsContainingPoint(pos,eps,elts);
4074   if(elts.empty())
4075     return -1;
4076   return elts.front();
4077 }
4078
4079 /*!
4080  * Finds cells in contact with a ball (i.e. a point with precision).
4081  * 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.
4082  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4083  * \warning This method is suitable if the caller intends to evaluate only one
4084  *          point, for more points getCellsContainingPoints() is recommended as it is
4085  *          faster.
4086  *  \param [in] pos - array of coordinates of the ball central point.
4087  *  \param [in] eps - ball radius.
4088  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4089  *         before inserting ids.
4090  *  \throw If the coordinates array is not set.
4091  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4092  *
4093  *  \if ENABLE_EXAMPLES
4094  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4095  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4096  *  \endif
4097  */
4098 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4099 {
4100   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4101   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4102   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4103 }
4104
4105 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4106                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4107                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4108 {
4109   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4110   if(spaceDim==3)
4111     {
4112       if(mDim==3)
4113         {
4114           const double *coords=_coords->getConstPointer();
4115           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4116         }
4117       else
4118         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4119     }
4120   else if(spaceDim==2)
4121     {
4122       if(mDim==2)
4123         {
4124           const double *coords=_coords->getConstPointer();
4125           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4126         }
4127       else
4128         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4129     }
4130   else if(spaceDim==1)
4131     {
4132       if(mDim==1)
4133         {
4134           const double *coords=_coords->getConstPointer();
4135           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4136         }
4137       else
4138         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4139     }
4140   else
4141     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4142 }
4143
4144 /*!
4145  * Finds cells in contact with several balls (i.e. points with precision).
4146  * This method is an extension of getCellContainingPoint() and
4147  * getCellsContainingPoint() for the case of multiple points.
4148  * 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.
4149  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4150  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4151  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4152  *         this->getSpaceDimension() * \a nbOfPoints
4153  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4154  *  \param [in] eps - radius of balls (i.e. the precision).
4155  *  \param [out] elts - vector returning ids of found cells.
4156  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4157  *         dividing cell ids in \a elts into groups each referring to one
4158  *         point. Its every element (except the last one) is an index pointing to the
4159  *         first id of a group of cells. For example cells in contact with the *i*-th
4160  *         point are described by following range of indices:
4161  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4162  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4163  *         Number of cells in contact with the *i*-th point is
4164  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4165  *  \throw If the coordinates array is not set.
4166  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4167  *
4168  *  \if ENABLE_EXAMPLES
4169  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4170  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4171  *  \endif
4172  */
4173 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4174                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4175 {
4176   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4177   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4178 }
4179
4180 /*!
4181  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4182  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4183  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4184  * 
4185  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4186  */
4187 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4188 {
4189   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4190   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4191 }
4192
4193 /*!
4194  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4195  * least two its edges intersect each other anywhere except their extremities. An
4196  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4197  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4198  *         cleared before filling in.
4199  *  \param [in] eps - precision.
4200  *  \throw If \a this->getMeshDimension() != 2.
4201  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4202  */
4203 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4204 {
4205   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4206   if(getMeshDimension()!=2)
4207     throw INTERP_KERNEL::Exception(msg);
4208   int spaceDim=getSpaceDimension();
4209   if(spaceDim!=2 && spaceDim!=3)
4210     throw INTERP_KERNEL::Exception(msg);
4211   const mcIdType *conn=_nodal_connec->getConstPointer();
4212   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4213   mcIdType nbOfCells=getNumberOfCells();
4214   std::vector<double> cell2DinS2;
4215   for(mcIdType i=0;i<nbOfCells;i++)
4216     {
4217       mcIdType offset=connI[i];
4218       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4219       if(nbOfNodesForCell<=3)
4220         continue;
4221       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4222       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4223       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4224         cells.push_back(i);
4225       cell2DinS2.clear();
4226     }
4227 }
4228
4229 /*!
4230  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4231  *
4232  * 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.
4233  * 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.
4234  *
4235  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4236  * This convex envelop is computed using Jarvis march algorithm.
4237  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4238  * 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)
4239  * 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.
4240  *
4241  * \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.
4242  * \sa MEDCouplingUMesh::colinearize2D
4243  */
4244 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4245 {
4246   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4247     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4248   checkFullyDefined();
4249   const double *coords=getCoords()->getConstPointer();
4250   mcIdType nbOfCells=getNumberOfCells();
4251   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4252   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4253   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4254   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4255   *workIndexOut=0;
4256   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4257   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4258   std::set<INTERP_KERNEL::NormalizedCellType> types;
4259   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4260   isChanged->alloc(0,1);
4261   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4262     {
4263       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4264       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4265         isChanged->pushBackSilent(i);
4266       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4267       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4268     }
4269   if(isChanged->empty())
4270     return 0;
4271   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4272   _types=types;
4273   return isChanged.retn();
4274 }
4275
4276 /*!
4277  * This method is \b NOT const because it can modify \a this.
4278  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4279  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4280  * \param policy specifies the type of extrusion chosen:
4281  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4282  *   will be repeated to build each level
4283  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4284  *   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
4285  *   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
4286  *   arc.
4287  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4288  */
4289 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4290 {
4291   checkFullyDefined();
4292   mesh1D->checkFullyDefined();
4293   if(!mesh1D->isContiguous1D())
4294     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4295   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4296     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4297   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4298     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4299   if(mesh1D->getMeshDimension()!=1)
4300     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4301   bool isQuad=false;
4302   if(isPresenceOfQuadratic())
4303     {
4304       if(mesh1D->isFullyQuadratic())
4305         isQuad=true;
4306       else
4307         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4308     }
4309   mcIdType oldNbOfNodes(getNumberOfNodes());
4310   MCAuto<DataArrayDouble> newCoords;
4311   switch(policy)
4312   {
4313     case 0:
4314       {
4315         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4316         break;
4317       }
4318     case 1:
4319       {
4320         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4321         break;
4322       }
4323     default:
4324       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4325   }
4326   setCoords(newCoords);
4327   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4328   updateTime();
4329   return ret.retn();
4330 }
4331
4332
4333 /*!
4334  * Checks if \a this mesh is constituted by only quadratic cells.
4335  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4336  *  \throw If the coordinates array is not set.
4337  *  \throw If the nodal connectivity of cells is not defined.
4338  */
4339 bool MEDCouplingUMesh::isFullyQuadratic() const
4340 {
4341   checkFullyDefined();
4342   bool ret=true;
4343   mcIdType nbOfCells=getNumberOfCells();
4344   for(mcIdType i=0;i<nbOfCells && ret;i++)
4345     {
4346       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4347       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4348       ret=cm.isQuadratic();
4349     }
4350   return ret;
4351 }
4352
4353 /*!
4354  * Checks if \a this mesh includes any quadratic cell.
4355  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4356  *  \throw If the coordinates array is not set.
4357  *  \throw If the nodal connectivity of cells is not defined.
4358  */
4359 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4360 {
4361   checkFullyDefined();
4362   bool ret=false;
4363   mcIdType nbOfCells=getNumberOfCells();
4364   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4365     {
4366       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4367       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4368       ret=cm.isQuadratic();
4369     }
4370   return ret;
4371 }
4372
4373 /*!
4374  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4375  * this mesh, it remains unchanged.
4376  *  \throw If the coordinates array is not set.
4377  *  \throw If the nodal connectivity of cells is not defined.
4378  */
4379 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4380 {
4381   checkFullyDefined();
4382   mcIdType nbOfCells=getNumberOfCells();
4383   mcIdType delta=0;
4384   const mcIdType *iciptr=_nodal_connec_index->begin();
4385   for(mcIdType i=0;i<nbOfCells;i++)
4386     {
4387       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4388       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4389       if(cm.isQuadratic())
4390         {
4391           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4392           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4393           if(!cml.isDynamic())
4394             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4395           else
4396             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4397         }
4398     }
4399   if(delta==0)
4400     return ;
4401   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4402   const mcIdType *icptr(_nodal_connec->begin());
4403   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4404   newConnI->alloc(nbOfCells+1,1);
4405   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4406   *ociptr=0;
4407   _types.clear();
4408   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4409     {
4410       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4411       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4412       if(!cm.isQuadratic())
4413         {
4414           _types.insert(type);
4415           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4416           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4417         }
4418       else
4419         {
4420           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4421           _types.insert(typel);
4422           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4423           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4424           if(cml.isDynamic())
4425             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4426           *ocptr++=ToIdType(typel);
4427           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4428           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4429         }
4430     }
4431   setConnectivity(newConn,newConnI,false);
4432 }
4433
4434 /*!
4435  * This method converts all linear cell in \a this to quadratic one.
4436  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4437  * 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)
4438  * 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.
4439  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4440  * end of the existing coordinates.
4441  *
4442  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4443  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4444  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4445  *
4446  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4447  *
4448  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4449  */
4450 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4451 {
4452   DataArrayIdType *conn=0,*connI=0;
4453   DataArrayDouble *coords=0;
4454   std::set<INTERP_KERNEL::NormalizedCellType> types;
4455   checkFullyDefined();
4456   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4457   MCAuto<DataArrayDouble> coordsSafe;
4458   int meshDim=getMeshDimension();
4459   switch(conversionType)
4460   {
4461     case 0:
4462       switch(meshDim)
4463       {
4464         case 1:
4465           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4466           connSafe=conn; connISafe=connI; coordsSafe=coords;
4467           break;
4468         case 2:
4469           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4470           connSafe=conn; connISafe=connI; coordsSafe=coords;
4471           break;
4472         case 3:
4473           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4474           connSafe=conn; connISafe=connI; coordsSafe=coords;
4475           break;
4476         default:
4477           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4478       }
4479       break;
4480         case 1:
4481           {
4482             switch(meshDim)
4483             {
4484               case 1:
4485                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4486                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4487                 break;
4488               case 2:
4489                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4490                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4491                 break;
4492               case 3:
4493                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4494                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4495                 break;
4496               default:
4497                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4498             }
4499             break;
4500           }
4501         default:
4502           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4503   }
4504   setConnectivity(connSafe,connISafe,false);
4505   _types=types;
4506   setCoords(coordsSafe);
4507   return ret.retn();
4508 }
4509
4510 /*!
4511  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4512  * so that the number of cells remains the same. Quadratic faces are converted to
4513  * polygons. This method works only for 2D meshes in
4514  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4515  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4516  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4517  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4518  *         a polylinized edge constituting the input polygon.
4519  *  \throw If the coordinates array is not set.
4520  *  \throw If the nodal connectivity of cells is not defined.
4521  *  \throw If \a this->getMeshDimension() != 2.
4522  *  \throw If \a this->getSpaceDimension() != 2.
4523  */
4524 void MEDCouplingUMesh::tessellate2D(double eps)
4525 {
4526   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4527   if(spaceDim!=2)
4528     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4529   switch(meshDim)
4530     {
4531     case 1:
4532       return tessellate2DCurveInternal(eps);
4533     case 2:
4534       return tessellate2DInternal(eps);
4535     default:
4536       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4537     }
4538 }
4539
4540 #if 0
4541 /*!
4542  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4543  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4544  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4545  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4546  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4547  * This method can be seen as the opposite method of colinearize2D.
4548  * 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
4549  * to avoid to modify the numbering of existing nodes.
4550  *
4551  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4552  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4553  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4554  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4555  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4556  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4557  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4558  *
4559  * \sa buildDescendingConnectivity2
4560  */
4561 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4562                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4563 {
4564   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4565     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4566   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4567   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4568     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4569   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4570     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4571   //DataArrayIdType *out0(0),*outi0(0);
4572   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4573   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4574   //out0s=out0s->buildUnique(); out0s->sort(true);
4575 }
4576 #endif
4577
4578
4579 /*!
4580  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4581  * In addition, returns an array mapping new cells to old ones. <br>
4582  * This method typically increases the number of cells in \a this mesh
4583  * but the number of nodes remains \b unchanged.
4584  * That's why the 3D splitting policies
4585  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4586  *  \param [in] policy - specifies a pattern used for splitting.
4587  * The semantic of \a policy is:
4588  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4589  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4590  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4591  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4592  *
4593  *
4594  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4595  *          an id of old cell producing it. The caller is to delete this array using
4596  *         decrRef() as it is no more needed.
4597  *
4598  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4599  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4600  *          and \a this->getMeshDimension() != 3.
4601  *  \throw If \a policy is not one of the four discussed above.
4602  *  \throw If the nodal connectivity of cells is not defined.
4603  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4604  */
4605 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4606 {
4607   switch(policy)
4608   {
4609     case 0:
4610       return simplexizePol0();
4611     case 1:
4612       return simplexizePol1();
4613     case INTERP_KERNEL::PLANAR_FACE_5:
4614         return simplexizePlanarFace5();
4615     case INTERP_KERNEL::PLANAR_FACE_6:
4616         return simplexizePlanarFace6();
4617     default:
4618       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)");
4619   }
4620 }
4621
4622 /*!
4623  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4624  * - 1D: INTERP_KERNEL::NORM_SEG2
4625  * - 2D: INTERP_KERNEL::NORM_TRI3
4626  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4627  *
4628  * This method is useful for users that need to use P1 field services as
4629  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4630  * All these methods need mesh support containing only simplex cells.
4631  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4632  *  \throw If the coordinates array is not set.
4633  *  \throw If the nodal connectivity of cells is not defined.
4634  *  \throw If \a this->getMeshDimension() < 1.
4635  */
4636 bool MEDCouplingUMesh::areOnlySimplexCells() const
4637 {
4638   checkFullyDefined();
4639   int mdim=getMeshDimension();
4640   if(mdim<1 || mdim>3)
4641     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4642   mcIdType nbCells=getNumberOfCells();
4643   const mcIdType *conn=_nodal_connec->begin();
4644   const mcIdType *connI=_nodal_connec_index->begin();
4645   for(mcIdType i=0;i<nbCells;i++)
4646     {
4647       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4648       if(!cm.isSimplex())
4649         return false;
4650     }
4651   return true;
4652 }
4653
4654
4655
4656 /*!
4657  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4658  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4659  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4660  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4661  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4662  * so it can be useful to call mergeNodes() before calling this method.
4663  *  \throw If \a this->getMeshDimension() <= 1.
4664  *  \throw If the coordinates array is not set.
4665  *  \throw If the nodal connectivity of cells is not defined.
4666  */
4667 void MEDCouplingUMesh::convertDegeneratedCells()
4668 {
4669   checkFullyDefined();
4670   if(getMeshDimension()<=1)
4671     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4672   mcIdType nbOfCells=getNumberOfCells();
4673   if(nbOfCells<1)
4674     return ;
4675   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4676   mcIdType *conn=_nodal_connec->getPointer();
4677   mcIdType *index=_nodal_connec_index->getPointer();
4678   mcIdType posOfCurCell=0;
4679   mcIdType newPos=0;
4680   mcIdType lgthOfCurCell;
4681   for(mcIdType i=0;i<nbOfCells;i++)
4682     {
4683       lgthOfCurCell=index[i+1]-posOfCurCell;
4684       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4685       mcIdType newLgth;
4686       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4687                                                                                                      conn+newPos+1,newLgth);
4688       conn[newPos]=newType;
4689       newPos+=newLgth+1;
4690       posOfCurCell=index[i+1];
4691       index[i+1]=newPos;
4692     }
4693   if(newPos!=initMeshLgth)
4694     _nodal_connec->reAlloc(newPos);
4695   computeTypes();
4696 }
4697
4698 /*!
4699  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4700  * A cell is flat in the following cases:
4701  *   - for a linear cell, all points in the connectivity are equal
4702  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4703  *   identical quadratic points
4704  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4705  *      this array using decrRef() as it is no more needed.
4706  */
4707 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4708 {
4709   checkFullyDefined();
4710   if(getMeshDimension()<=1)
4711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4712   mcIdType nbOfCells=getNumberOfCells();
4713   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4714   if(nbOfCells<1)
4715     return ret.retn();
4716   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4717   mcIdType *conn=_nodal_connec->getPointer();
4718   mcIdType *index=_nodal_connec_index->getPointer();
4719   mcIdType posOfCurCell=0;
4720   mcIdType newPos=0;
4721   mcIdType lgthOfCurCell, nbDelCells(0);
4722   for(mcIdType i=0;i<nbOfCells;i++)
4723     {
4724       lgthOfCurCell=index[i+1]-posOfCurCell;
4725       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4726       mcIdType newLgth;
4727       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4728                                                                                                      conn+newPos+1,newLgth);
4729       // Shall we delete the cell if it is completely degenerated:
4730       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4731       if (delCell)
4732         {
4733           nbDelCells++;
4734           ret->pushBackSilent(i);
4735         }
4736       else   //if the cell is to be deleted, simply stay at the same place
4737         {
4738           conn[newPos]=newType;
4739           newPos+=newLgth+1;
4740         }
4741       posOfCurCell=index[i+1];
4742       index[i+1-nbDelCells]=newPos;
4743     }
4744   if(newPos!=initMeshLgth)
4745     _nodal_connec->reAlloc(newPos);
4746   const mcIdType nCellDel=ret->getNumberOfTuples();
4747   if (nCellDel)
4748     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4749   computeTypes();
4750   return ret.retn();
4751 }
4752
4753 /*!
4754  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4755  * Only connectivity is considered here.
4756  */
4757 bool MEDCouplingUMesh::removeDegenerated1DCells()
4758 {
4759   checkConnectivityFullyDefined();
4760   if(getMeshDimension()!=1)
4761     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4762   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4763   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4764   {
4765     for(std::size_t i=0;i<nbCells;i++)
4766       {
4767         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4768         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4769           {
4770             if(conn[conni[i]+1]!=conn[conni[i]+2])
4771               {
4772                 newSize++;
4773                 newSize2+=conni[i+1]-conni[i];
4774               }
4775           }
4776         else
4777           {
4778             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4779             throw INTERP_KERNEL::Exception(oss.str());
4780           }
4781       }
4782   }
4783   if(newSize==nbCells)//no cells has been removed -> do nothing
4784     return false;
4785   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4786   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4787   for(std::size_t i=0;i<nbCells;i++)
4788     {
4789       if(conn[conni[i]+1]!=conn[conni[i]+2])
4790         {
4791           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4792           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4793           newConnIPtr++;
4794         }
4795     }
4796   setConnectivity(newConn,newConnI,true);
4797   return true;
4798 }
4799
4800 /*!
4801  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4802  * A cell is considered to be oriented correctly if an angle between its
4803  * normal vector and a given vector is less than \c PI / \c 2.
4804  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4805  *         cells.
4806  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4807  *         checked.
4808  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4809  *         is not cleared before filling in.
4810  *  \throw If \a this->getMeshDimension() != 2.
4811  *  \throw If \a this->getSpaceDimension() != 3.
4812  *
4813  *  \if ENABLE_EXAMPLES
4814  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4815  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4816  *  \endif
4817  */
4818 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4819 {
4820   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4821     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4822   mcIdType nbOfCells=getNumberOfCells();
4823   const mcIdType *conn=_nodal_connec->begin();
4824   const mcIdType *connI=_nodal_connec_index->begin();
4825   const double *coordsPtr=_coords->begin();
4826   for(mcIdType i=0;i<nbOfCells;i++)
4827     {
4828       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4829       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4830         {
4831           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4832           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4833             cells.push_back(i);
4834         }
4835     }
4836 }
4837
4838 /*!
4839  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4840  * considered to be oriented correctly if an angle between its normal vector and a
4841  * given vector is less than \c PI / \c 2.
4842  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4843  *         cells.
4844  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4845  *         checked.
4846  *  \throw If \a this->getMeshDimension() != 2.
4847  *  \throw If \a this->getSpaceDimension() != 3.
4848  *
4849  *  \if ENABLE_EXAMPLES
4850  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4851  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4852  *  \endif
4853  *
4854  *  \sa changeOrientationOfCells
4855  */
4856 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4857 {
4858   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4859     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4860   mcIdType nbOfCells=getNumberOfCells();
4861   mcIdType *conn(_nodal_connec->getPointer());
4862   const mcIdType *connI(_nodal_connec_index->begin());
4863   const double *coordsPtr(_coords->begin());
4864   bool isModified(false);
4865   for(mcIdType i=0;i<nbOfCells;i++)
4866     {
4867       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4868       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4869         {
4870           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4871           bool isQuadratic(cm.isQuadratic());
4872           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4873             {
4874               isModified=true;
4875               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4876             }
4877         }
4878     }
4879   if(isModified)
4880     _nodal_connec->declareAsNew();
4881   updateTime();
4882 }
4883
4884 /*!
4885  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4886  *
4887  * \sa orientCorrectly2DCells
4888  */
4889 void MEDCouplingUMesh::changeOrientationOfCells()
4890 {
4891   int mdim(getMeshDimension());
4892   if(mdim!=2 && mdim!=1)
4893     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4894   mcIdType nbOfCells=getNumberOfCells();
4895   mcIdType *conn(_nodal_connec->getPointer());
4896   const mcIdType *connI(_nodal_connec_index->begin());
4897   if(mdim==2)
4898     {//2D
4899       for(mcIdType i=0;i<nbOfCells;i++)
4900         {
4901           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4902           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4903           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4904         }
4905     }
4906   else
4907     {//1D
4908       for(mcIdType i=0;i<nbOfCells;i++)
4909         {
4910           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4911           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4912           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4913         }
4914     }
4915 }
4916
4917 /*!
4918  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4919  * oriented facets. The normal vector of the facet should point out of the cell.
4920  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4921  *         is not cleared before filling in.
4922  *  \throw If \a this->getMeshDimension() != 3.
4923  *  \throw If \a this->getSpaceDimension() != 3.
4924  *  \throw If the coordinates array is not set.
4925  *  \throw If the nodal connectivity of cells is not defined.
4926  *
4927  *  \if ENABLE_EXAMPLES
4928  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4929  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4930  *  \endif
4931  */
4932 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4933 {
4934   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4935     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4936   mcIdType nbOfCells=getNumberOfCells();
4937   const mcIdType *conn=_nodal_connec->begin();
4938   const mcIdType *connI=_nodal_connec_index->begin();
4939   const double *coordsPtr=_coords->begin();
4940   for(mcIdType i=0;i<nbOfCells;i++)
4941     {
4942       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4943       if(type==INTERP_KERNEL::NORM_POLYHED)
4944         {
4945           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4946             cells.push_back(i);
4947         }
4948     }
4949 }
4950
4951 /*!
4952  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4953  * out of the cell.
4954  *  \throw If \a this->getMeshDimension() != 3.
4955  *  \throw If \a this->getSpaceDimension() != 3.
4956  *  \throw If the coordinates array is not set.
4957  *  \throw If the nodal connectivity of cells is not defined.
4958  *  \throw If the reparation fails.
4959  *
4960  *  \if ENABLE_EXAMPLES
4961  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4962  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4963  *  \endif
4964  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4965  */
4966 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4967 {
4968   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4969     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4970   mcIdType nbOfCells=getNumberOfCells();
4971   mcIdType *conn=_nodal_connec->getPointer();
4972   const mcIdType *connI=_nodal_connec_index->begin();
4973   const double *coordsPtr=_coords->begin();
4974   for(mcIdType i=0;i<nbOfCells;i++)
4975     {
4976       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4977       if(type==INTERP_KERNEL::NORM_POLYHED)
4978         {
4979           try
4980           {
4981               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4982                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4983           }
4984           catch(INTERP_KERNEL::Exception& e)
4985           {
4986               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4987               throw INTERP_KERNEL::Exception(oss.str());
4988           }
4989         }
4990     }
4991   updateTime();
4992 }
4993
4994 /*!
4995  * This method invert orientation of all cells in \a this.
4996  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4997  * This method only operates on the connectivity so coordinates are not touched at all.
4998  */
4999 void MEDCouplingUMesh::invertOrientationOfAllCells()
5000 {
5001   checkConnectivityFullyDefined();
5002   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5003   mcIdType *conn(_nodal_connec->getPointer());
5004   const mcIdType *conni(_nodal_connec_index->begin());
5005   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5006     {
5007       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5008       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5009       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5010         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5011     }
5012   updateTime();
5013 }
5014
5015 /*!
5016  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5017  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5018  * according to which the first facet of the cell should be oriented to have the normal vector
5019  * pointing out of cell.
5020  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5021  *         cells. The caller is to delete this array using decrRef() as it is no more
5022  *         needed.
5023  *  \throw If \a this->getMeshDimension() != 3.
5024  *  \throw If \a this->getSpaceDimension() != 3.
5025  *  \throw If the coordinates array is not set.
5026  *  \throw If the nodal connectivity of cells is not defined.
5027  *
5028  *  \if ENABLE_EXAMPLES
5029  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5030  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5031  *  \endif
5032  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5033  */
5034 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5035 {
5036   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5037   if(getMeshDimension()!=3)
5038     throw INTERP_KERNEL::Exception(msg);
5039   int spaceDim=getSpaceDimension();
5040   if(spaceDim!=3)
5041     throw INTERP_KERNEL::Exception(msg);
5042   //
5043   mcIdType nbOfCells=getNumberOfCells();
5044   mcIdType *conn=_nodal_connec->getPointer();
5045   const mcIdType *connI=_nodal_connec_index->begin();
5046   const double *coo=getCoords()->begin();
5047   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5048   for(mcIdType i=0;i<nbOfCells;i++)
5049     {
5050       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5051       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5052         {
5053           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5054             {
5055               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5056               cells->pushBackSilent(i);
5057             }
5058         }
5059     }
5060   return cells.retn();
5061 }
5062
5063 /*!
5064  * This method is a faster method to correct orientation of all 3D cells in \a this.
5065  * 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.
5066  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5067  *
5068  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5069  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5070  */
5071 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5072 {
5073   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5074     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5075   mcIdType nbOfCells=getNumberOfCells();
5076   mcIdType *conn=_nodal_connec->getPointer();
5077   const mcIdType *connI=_nodal_connec_index->begin();
5078   const double *coordsPtr=_coords->begin();
5079   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5080   for(mcIdType i=0;i<nbOfCells;i++)
5081     {
5082       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5083       switch(type)
5084       {
5085         case INTERP_KERNEL::NORM_TETRA4:
5086           {
5087             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5088               {
5089                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5090                 ret->pushBackSilent(i);
5091               }
5092             break;
5093           }
5094         case INTERP_KERNEL::NORM_PYRA5:
5095           {
5096             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5097               {
5098                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5099                 ret->pushBackSilent(i);
5100               }
5101             break;
5102           }
5103         case INTERP_KERNEL::NORM_PENTA6:
5104         case INTERP_KERNEL::NORM_HEXA8:
5105         case INTERP_KERNEL::NORM_HEXGP12:
5106           {
5107             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5108               {
5109                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5110                 ret->pushBackSilent(i);
5111               }
5112             break;
5113           }
5114         case INTERP_KERNEL::NORM_POLYHED:
5115           {
5116             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5117               {
5118                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5119                 ret->pushBackSilent(i);
5120               }
5121             break;
5122           }
5123         default:
5124           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 !");
5125       }
5126     }
5127   updateTime();
5128   return ret.retn();
5129 }
5130
5131 /*!
5132  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5133  * If it is not the case an exception will be thrown.
5134  * This method is fast because the first cell of \a this is used to compute the plane.
5135  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5136  * \param pos output of size at least 3 used to store a point owned of searched plane.
5137  */
5138 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5139 {
5140   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5141     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5142   const mcIdType *conn=_nodal_connec->begin();
5143   const mcIdType *connI=_nodal_connec_index->begin();
5144   const double *coordsPtr=_coords->begin();
5145   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5146   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5147 }
5148
5149 /*!
5150  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5151  * cells. Currently cells of the following types are treated:
5152  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5153  * For a cell of other type an exception is thrown.
5154  * Space dimension of a 2D mesh can be either 2 or 3.
5155  * The Edge Ratio of a cell \f$t\f$ is:
5156  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5157  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5158  *  the smallest edge lengths of \f$t\f$.
5159  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5160  *          cells and one time, lying on \a this mesh. The caller is to delete this
5161  *          field using decrRef() as it is no more needed.
5162  *  \throw If the coordinates array is not set.
5163  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5164  *  \throw If the connectivity data array has more than one component.
5165  *  \throw If the connectivity data array has a named component.
5166  *  \throw If the connectivity index data array has more than one component.
5167  *  \throw If the connectivity index data array has a named component.
5168  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5169  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5170  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5171  */
5172 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5173 {
5174   checkConsistencyLight();
5175   int spaceDim=getSpaceDimension();
5176   int meshDim=getMeshDimension();
5177   if(spaceDim!=2 && spaceDim!=3)
5178     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5179   if(meshDim!=2 && meshDim!=3)
5180     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5181   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5182   ret->setMesh(this);
5183   mcIdType nbOfCells=getNumberOfCells();
5184   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5185   arr->alloc(nbOfCells,1);
5186   double *pt=arr->getPointer();
5187   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5188   const mcIdType *conn=_nodal_connec->begin();
5189   const mcIdType *connI=_nodal_connec_index->begin();
5190   const double *coo=_coords->begin();
5191   double tmp[12];
5192   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5193     {
5194       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5195       switch(t)
5196       {
5197         case INTERP_KERNEL::NORM_TRI3:
5198           {
5199             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5200             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5201             break;
5202           }
5203         case INTERP_KERNEL::NORM_QUAD4:
5204           {
5205             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5206             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5207             break;
5208           }
5209         case INTERP_KERNEL::NORM_TETRA4:
5210           {
5211             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5212             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5213             break;
5214           }
5215         default:
5216           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5217       }
5218       conn+=connI[i+1]-connI[i];
5219     }
5220   ret->setName("EdgeRatio");
5221   ret->synchronizeTimeWithSupport();
5222   return ret.retn();
5223 }
5224
5225 /*!
5226  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5227  * cells. Currently cells of the following types are treated:
5228  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5229  * For a cell of other type an exception is thrown.
5230  * Space dimension of a 2D mesh can be either 2 or 3.
5231  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5232  *          cells and one time, lying on \a this mesh. The caller is to delete this
5233  *          field using decrRef() as it is no more needed.
5234  *  \throw If the coordinates array is not set.
5235  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5236  *  \throw If the connectivity data array has more than one component.
5237  *  \throw If the connectivity data array has a named component.
5238  *  \throw If the connectivity index data array has more than one component.
5239  *  \throw If the connectivity index data array has a named component.
5240  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5241  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5242  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5243  */
5244 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5245 {
5246   checkConsistencyLight();
5247   int spaceDim=getSpaceDimension();
5248   int meshDim=getMeshDimension();
5249   if(spaceDim!=2 && spaceDim!=3)
5250     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5251   if(meshDim!=2 && meshDim!=3)
5252     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5253   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5254   ret->setMesh(this);
5255   mcIdType nbOfCells=getNumberOfCells();
5256   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5257   arr->alloc(nbOfCells,1);
5258   double *pt=arr->getPointer();
5259   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5260   const mcIdType *conn=_nodal_connec->begin();
5261   const mcIdType *connI=_nodal_connec_index->begin();
5262   const double *coo=_coords->begin();
5263   double tmp[12];
5264   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5265     {
5266       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5267       switch(t)
5268       {
5269         case INTERP_KERNEL::NORM_TRI3:
5270           {
5271             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5272             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5273             break;
5274           }
5275         case INTERP_KERNEL::NORM_QUAD4:
5276           {
5277             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5278             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5279             break;
5280           }
5281         case INTERP_KERNEL::NORM_TETRA4:
5282           {
5283             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5284             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5285             break;
5286           }
5287         default:
5288           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5289       }
5290       conn+=connI[i+1]-connI[i];
5291     }
5292   ret->setName("AspectRatio");
5293   ret->synchronizeTimeWithSupport();
5294   return ret.retn();
5295 }
5296
5297 /*!
5298  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5299  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5300  * in 3D space. Currently only cells of the following types are
5301  * treated: INTERP_KERNEL::NORM_QUAD4.
5302  * For a cell of other type an exception is thrown.
5303  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5304  * Defining
5305  * \f$t=\vec{da}\times\vec{ab}\f$,
5306  * \f$u=\vec{ab}\times\vec{bc}\f$
5307  * \f$v=\vec{bc}\times\vec{cd}\f$
5308  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5309  *  \f[
5310  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5311  *  \f]
5312  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5313  *          cells and one time, lying on \a this mesh. The caller is to delete this
5314  *          field using decrRef() as it is no more needed.
5315  *  \throw If the coordinates array is not set.
5316  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5317  *  \throw If the connectivity data array has more than one component.
5318  *  \throw If the connectivity data array has a named component.
5319  *  \throw If the connectivity index data array has more than one component.
5320  *  \throw If the connectivity index data array has a named component.
5321  *  \throw If \a this->getMeshDimension() != 2.
5322  *  \throw If \a this->getSpaceDimension() != 3.
5323  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5324  */
5325 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5326 {
5327   checkConsistencyLight();
5328   int spaceDim=getSpaceDimension();
5329   int meshDim=getMeshDimension();
5330   if(spaceDim!=3)
5331     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5332   if(meshDim!=2)
5333     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5334   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5335   ret->setMesh(this);
5336   mcIdType nbOfCells=getNumberOfCells();
5337   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5338   arr->alloc(nbOfCells,1);
5339   double *pt=arr->getPointer();
5340   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5341   const mcIdType *conn=_nodal_connec->begin();
5342   const mcIdType *connI=_nodal_connec_index->begin();
5343   const double *coo=_coords->begin();
5344   double tmp[12];
5345   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5346     {
5347       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5348       switch(t)
5349       {
5350         case INTERP_KERNEL::NORM_QUAD4:
5351           {
5352             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5353             *pt=INTERP_KERNEL::quadWarp(tmp);
5354             break;
5355           }
5356         default:
5357           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5358       }
5359       conn+=connI[i+1]-connI[i];
5360     }
5361   ret->setName("Warp");
5362   ret->synchronizeTimeWithSupport();
5363   return ret.retn();
5364 }
5365
5366
5367 /*!
5368  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5369  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5370  * treated: INTERP_KERNEL::NORM_QUAD4.
5371  * The skew is computed as follow for a quad with points (a,b,c,d): let
5372  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5373  * then the skew is computed as:
5374  *  \f[
5375  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5376  *  \f]
5377  *
5378  * For a cell of other type an exception is thrown.
5379  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5380  *          cells and one time, lying on \a this mesh. The caller is to delete this
5381  *          field using decrRef() as it is no more needed.
5382  *  \throw If the coordinates array is not set.
5383  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5384  *  \throw If the connectivity data array has more than one component.
5385  *  \throw If the connectivity data array has a named component.
5386  *  \throw If the connectivity index data array has more than one component.
5387  *  \throw If the connectivity index data array has a named component.
5388  *  \throw If \a this->getMeshDimension() != 2.
5389  *  \throw If \a this->getSpaceDimension() != 3.
5390  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5391  */
5392 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5393 {
5394   checkConsistencyLight();
5395   int spaceDim=getSpaceDimension();
5396   int meshDim=getMeshDimension();
5397   if(spaceDim!=3)
5398     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5399   if(meshDim!=2)
5400     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5401   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5402   ret->setMesh(this);
5403   mcIdType nbOfCells=getNumberOfCells();
5404   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5405   arr->alloc(nbOfCells,1);
5406   double *pt=arr->getPointer();
5407   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5408   const mcIdType *conn=_nodal_connec->begin();
5409   const mcIdType *connI=_nodal_connec_index->begin();
5410   const double *coo=_coords->begin();
5411   double tmp[12];
5412   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5413     {
5414       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5415       switch(t)
5416       {
5417         case INTERP_KERNEL::NORM_QUAD4:
5418           {
5419             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5420             *pt=INTERP_KERNEL::quadSkew(tmp);
5421             break;
5422           }
5423         default:
5424           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5425       }
5426       conn+=connI[i+1]-connI[i];
5427     }
5428   ret->setName("Skew");
5429   ret->synchronizeTimeWithSupport();
5430   return ret.retn();
5431 }
5432
5433 /*!
5434  * 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.
5435  *
5436  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5437  *
5438  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5439  */
5440 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5441 {
5442   checkConsistencyLight();
5443   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5444   ret->setMesh(this);
5445   std::set<INTERP_KERNEL::NormalizedCellType> types;
5446   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5447   int spaceDim(getSpaceDimension());
5448   mcIdType nbCells(getNumberOfCells());
5449   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5450   arr->alloc(nbCells,1);
5451   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5452     {
5453       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5454       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5455       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5456     }
5457   ret->setArray(arr);
5458   ret->setName("Diameter");
5459   return ret.retn();
5460 }
5461
5462 /*!
5463  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5464  *
5465  * \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)
5466  *                         For all other cases this input parameter is ignored.
5467  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5468  *
5469  * \throw If \a this is not fully set (coordinates and connectivity).
5470  * \throw If a cell in \a this has no valid nodeId.
5471  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5472  */
5473 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5474 {
5475   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5476   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.
5477     return getBoundingBoxForBBTreeFast();
5478   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5479     {
5480       bool presenceOfQuadratic(false);
5481       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5482         {
5483           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5484           if(cm.isQuadratic())
5485             presenceOfQuadratic=true;
5486         }
5487       if(!presenceOfQuadratic)
5488         return getBoundingBoxForBBTreeFast();
5489       if(mDim==2 && sDim==2)
5490         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5491       else
5492         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5493     }
5494   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) !");
5495 }
5496
5497 /*!
5498  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5499  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5500  *
5501  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5502  *
5503  * \throw If \a this is not fully set (coordinates and connectivity).
5504  * \throw If a cell in \a this has no valid nodeId.
5505  */
5506 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5507 {
5508   checkFullyDefined();
5509   int spaceDim(getSpaceDimension());
5510   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5511   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5512   double *bbox(ret->getPointer());
5513   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5514     {
5515       bbox[2*i]=std::numeric_limits<double>::max();
5516       bbox[2*i+1]=-std::numeric_limits<double>::max();
5517     }
5518   const double *coordsPtr(_coords->begin());
5519   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5520   for(mcIdType i=0;i<nbOfCells;i++)
5521     {
5522       mcIdType offset=connI[i]+1;
5523       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5524       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5525         {
5526           mcIdType nodeId=conn[offset+j];
5527           if(nodeId>=0 && nodeId<nbOfNodes)
5528             {
5529               for(int k=0;k<spaceDim;k++)
5530                 {
5531                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5532                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5533                 }
5534               kk++;
5535             }
5536         }
5537       if(kk==0)
5538         {
5539           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5540           throw INTERP_KERNEL::Exception(oss.str());
5541         }
5542     }
5543   return ret.retn();
5544 }
5545
5546 /*!
5547  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5548  * useful for 2D meshes having quadratic cells
5549  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5550  * the two extremities of the arc of circle).
5551  *
5552  * \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)
5553  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5554  * \throw If \a this is not fully defined.
5555  * \throw If \a this is not a mesh with meshDimension equal to 2.
5556  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5557  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5558  */
5559 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5560 {
5561   checkFullyDefined();
5562   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5563
5564   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5565   mcIdType nbOfCells=getNumberOfCells();
5566   if(spaceDim!=2 || mDim!=2)
5567     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!");
5568   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5569   double *bbox(ret->getPointer());
5570   const double *coords(_coords->begin());
5571   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5572   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5573     {
5574       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5575       mcIdType sz(connI[1]-connI[0]-1);
5576       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5577       INTERP_KERNEL::QuadraticPolygon *pol(0);
5578       for(mcIdType j=0;j<sz;j++)
5579         {
5580           mcIdType nodeId(conn[*connI+1+j]);
5581           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5582         }
5583       if(!cm.isQuadratic())
5584         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5585       else
5586         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5587       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5588       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5589     }
5590   return ret.retn();
5591 }
5592
5593 /*!
5594  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5595  * useful for 2D meshes having quadratic cells
5596  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5597  * the two extremities of the arc of circle).
5598  *
5599  * \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)
5600  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5601  * \throw If \a this is not fully defined.
5602  * \throw If \a this is not a mesh with meshDimension equal to 1.
5603  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5604  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5605  */
5606 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5607 {
5608   checkFullyDefined();
5609   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5610   mcIdType nbOfCells=getNumberOfCells();
5611   if(spaceDim!=2 || mDim!=1)
5612     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!");
5613   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5614   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5615   double *bbox(ret->getPointer());
5616   const double *coords(_coords->begin());
5617   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5618   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5619     {
5620       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5621       mcIdType sz(connI[1]-connI[0]-1);
5622       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5623       INTERP_KERNEL::Edge *edge(0);
5624       for(mcIdType j=0;j<sz;j++)
5625         {
5626           mcIdType nodeId(conn[*connI+1+j]);
5627           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5628         }
5629       if(!cm.isQuadratic())
5630         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5631       else
5632         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5633       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5634       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5635     }
5636   return ret.retn();
5637 }
5638
5639 /// @cond INTERNAL
5640
5641 namespace MEDCouplingImpl
5642 {
5643   class ConnReader
5644   {
5645   public:
5646     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5647     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5648   private:
5649     const mcIdType *_conn;
5650     mcIdType _val;
5651   };
5652
5653   class ConnReader2
5654   {
5655   public:
5656     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5657     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5658   private:
5659     const mcIdType *_conn;
5660     mcIdType _val;
5661   };
5662 }
5663
5664 /// @endcond
5665
5666 /*!
5667  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5668  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5669  * \a this is composed in cell types.
5670  * The returned array is of size 3*n where n is the number of different types present in \a this.
5671  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5672  * This parameter is kept only for compatibility with other method listed above.
5673  */
5674 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5675 {
5676   checkConnectivityFullyDefined();
5677   const mcIdType *conn=_nodal_connec->begin();
5678   const mcIdType *connI=_nodal_connec_index->begin();
5679   const mcIdType *work=connI;
5680   mcIdType nbOfCells=getNumberOfCells();
5681   std::size_t n=getAllGeoTypes().size();
5682   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5683   std::set<INTERP_KERNEL::NormalizedCellType> types;
5684   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5685     {
5686       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5687       if(types.find(typ)!=types.end())
5688         {
5689           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5690           oss << " is not contiguous !";
5691           throw INTERP_KERNEL::Exception(oss.str());
5692         }
5693       types.insert(typ);
5694       ret[3*i]=typ;
5695       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5696       ret[3*i+1]=ToIdType(std::distance(work,work2));
5697       work=work2;
5698     }
5699   return ret;
5700 }
5701
5702 /*!
5703  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5704  * only for types cell, type node is not managed.
5705  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5706  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5707  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5708  * If 2 or more same geometric type is in \a code and exception is thrown too.
5709  *
5710  * This method firstly checks
5711  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5712  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5713  * an exception is thrown too.
5714  *
5715  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5716  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5717  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5718  */
5719 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5720 {
5721   if(code.empty())
5722     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5723   std::size_t sz=code.size();
5724   std::size_t n=sz/3;
5725   if(sz%3!=0)
5726     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5727   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5728   mcIdType nb=0;
5729   bool isNoPflUsed=true;
5730   for(std::size_t i=0;i<n;i++)
5731     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5732       {
5733         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5734         nb+=code[3*i+1];
5735         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5736           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5737         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5738       }
5739   if(types.size()!=n)
5740     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5741   if(isNoPflUsed)
5742     {
5743       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5744         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5745       if(types.size()==_types.size())
5746         return 0;
5747     }
5748   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5749   ret->alloc(nb,1);
5750   mcIdType *retPtr=ret->getPointer();
5751   const mcIdType *connI=_nodal_connec_index->begin();
5752   const mcIdType *conn=_nodal_connec->begin();
5753   mcIdType nbOfCells=getNumberOfCells();
5754   const mcIdType *i=connI;
5755   int kk=0;
5756   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5757     {
5758       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5759       mcIdType offset=ToIdType(std::distance(connI,i));
5760       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5761       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5762       if(code[3*kk+2]==-1)
5763         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5764           *retPtr++=k+offset;
5765       else
5766         {
5767           mcIdType idInIdsPerType=code[3*kk+2];
5768           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5769             {
5770               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5771               if(zePfl)
5772                 {
5773                   zePfl->checkAllocated();
5774                   if(zePfl->getNumberOfComponents()==1)
5775                     {
5776                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5777                         {
5778                           if(*k>=0 && *k<nbOfCellsOfCurType)
5779                             *retPtr=(*k)+offset;
5780                           else
5781                             {
5782                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5783                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5784                               throw INTERP_KERNEL::Exception(oss.str());
5785                             }
5786                         }
5787                     }
5788                   else
5789                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5790                 }
5791               else
5792                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5793             }
5794           else
5795             {
5796               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5797               oss << " should be in [0," << idsPerType.size() << ") !";
5798               throw INTERP_KERNEL::Exception(oss.str());
5799             }
5800         }
5801       i=j;
5802     }
5803   return ret.retn();
5804 }
5805
5806 /*!
5807  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5808  * 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.
5809  * 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.
5810  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5811  *
5812  * \param [in] profile list of IDs constituing the profile
5813  * \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.
5814  * \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,
5815  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5816  * \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.
5817  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5818  * \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
5819  */
5820 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5821 {
5822   if(!profile)
5823     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5824   if(profile->getNumberOfComponents()!=1)
5825     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5826   checkConnectivityFullyDefined();
5827   const mcIdType *conn=_nodal_connec->begin();
5828   const mcIdType *connI=_nodal_connec_index->begin();
5829   mcIdType nbOfCells=getNumberOfCells();
5830   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5831   std::vector<mcIdType> typeRangeVals(1);
5832   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5833     {
5834       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5835       if(std::find(types.begin(),types.end(),curType)!=types.end())
5836         {
5837           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5838         }
5839       types.push_back(curType);
5840       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5841       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5842     }
5843   //
5844   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5845   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5846   MCAuto<DataArrayIdType> tmp0=castArr;
5847   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5848   MCAuto<DataArrayIdType> tmp2=castsPresent;
5849   //
5850   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5851   code.resize(3*nbOfCastsFinal);
5852   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5853   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5854   for(mcIdType i=0;i<nbOfCastsFinal;i++)
5855     {
5856       mcIdType castId=castsPresent->getIJ(i,0);
5857       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5858       idsInPflPerType2.push_back(tmp3);
5859       code[3*i]=ToIdType(types[castId]);
5860       code[3*i+1]=tmp3->getNumberOfTuples();
5861       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5862       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5863         {
5864           tmp4->copyStringInfoFrom(*profile);
5865           idsPerType2.push_back(tmp4);
5866           code[3*i+2]=ToIdType(idsPerType2.size())-1;
5867         }
5868       else
5869         {
5870           code[3*i+2]=-1;
5871         }
5872     }
5873   std::size_t sz2=idsInPflPerType2.size();
5874   idsInPflPerType.resize(sz2);
5875   for(std::size_t i=0;i<sz2;i++)
5876     {
5877       DataArrayIdType *locDa=idsInPflPerType2[i];
5878       locDa->incrRef();
5879       idsInPflPerType[i]=locDa;
5880     }
5881   std::size_t sz=idsPerType2.size();
5882   idsPerType.resize(sz);
5883   for(std::size_t i=0;i<sz;i++)
5884     {
5885       DataArrayIdType *locDa=idsPerType2[i];
5886       locDa->incrRef();
5887       idsPerType[i]=locDa;
5888     }
5889 }
5890
5891 /*!
5892  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5893  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5894  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5895  * 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.
5896  */
5897 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5898 {
5899   checkFullyDefined();
5900   nM1LevMesh->checkFullyDefined();
5901   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5902     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5903   if(_coords!=nM1LevMesh->getCoords())
5904     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5905   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5906   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5907   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5908   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5909   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5910   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5911   tmp->setConnectivity(tmp0,tmp1);
5912   tmp->renumberCells(ret0->begin(),false);
5913   revDesc=tmp->getNodalConnectivity();
5914   revDescIndx=tmp->getNodalConnectivityIndex();
5915   DataArrayIdType *ret=0;
5916   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5917     {
5918       mcIdType tmp2;
5919       ret->getMaxValue(tmp2);
5920       ret->decrRef();
5921       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5922       throw INTERP_KERNEL::Exception(oss.str());
5923     }
5924   nM1LevMeshIds=ret;
5925   //
5926   revDesc->incrRef();
5927   revDescIndx->incrRef();
5928   ret1->incrRef();
5929   ret0->incrRef();
5930   meshnM1Old2New=ret0;
5931   return ret1;
5932 }
5933
5934 /*!
5935  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5936  * necessary for writing the mesh to MED file. Additionally returns a permutation array
5937  * in "Old to New" mode.
5938  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5939  *          this array using decrRef() as it is no more needed.
5940  *  \throw If the nodal connectivity of cells is not defined.
5941  */
5942 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5943 {
5944   checkConnectivityFullyDefined();
5945   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5946   renumberCells(ret->begin(),false);
5947   return ret.retn();
5948 }
5949
5950 /*!
5951  * This methods checks that cells are sorted by their types.
5952  * This method makes asumption (no check) that connectivity is correctly set before calling.
5953  */
5954 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5955 {
5956   checkFullyDefined();
5957   const mcIdType *conn=_nodal_connec->begin();
5958   const mcIdType *connI=_nodal_connec_index->begin();
5959   mcIdType nbOfCells=getNumberOfCells();
5960   std::set<INTERP_KERNEL::NormalizedCellType> types;
5961   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5962     {
5963       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5964       if(types.find(curType)!=types.end())
5965         return false;
5966       types.insert(curType);
5967       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5968     }
5969   return true;
5970 }
5971
5972 /*!
5973  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5974  * The geometric type order is specified by MED file.
5975  *
5976  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5977  */
5978 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5979 {
5980   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5981 }
5982
5983 /*!
5984  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5985  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5986  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5987  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5988  */
5989 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5990 {
5991   checkFullyDefined();
5992   const mcIdType *conn=_nodal_connec->begin();
5993   const mcIdType *connI=_nodal_connec_index->begin();
5994   mcIdType nbOfCells=getNumberOfCells();
5995   if(nbOfCells==0)
5996     return true;
5997   mcIdType lastPos=-1;
5998   std::set<INTERP_KERNEL::NormalizedCellType> sg;
5999   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6000     {
6001       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6002       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6003       if(isTypeExists!=orderEnd)
6004         {
6005           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6006           if(pos<=lastPos)
6007             return false;
6008           lastPos=pos;
6009           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6010         }
6011       else
6012         {
6013           if(sg.find(curType)==sg.end())
6014             {
6015               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6016               sg.insert(curType);
6017             }
6018           else
6019             return false;
6020         }
6021     }
6022   return true;
6023 }
6024
6025 /*!
6026  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6027  * 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
6028  * 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'.
6029  */
6030 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6031 {
6032   checkConnectivityFullyDefined();
6033   mcIdType nbOfCells=getNumberOfCells();
6034   const mcIdType *conn=_nodal_connec->begin();
6035   const mcIdType *connI=_nodal_connec_index->begin();
6036   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6037   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6038   tmpa->alloc(nbOfCells,1);
6039   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6040   tmpb->fillWithZero();
6041   mcIdType *tmp=tmpa->getPointer();
6042   mcIdType *tmp2=tmpb->getPointer();
6043   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6044     {
6045       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6046       if(where!=orderEnd)
6047         {
6048           mcIdType pos=ToIdType(std::distance(orderBg,where));
6049           tmp2[pos]++;
6050           tmp[std::distance(connI,i)]=pos;
6051         }
6052       else
6053         {
6054           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6055           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6056           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6057           throw INTERP_KERNEL::Exception(oss.str());
6058         }
6059     }
6060   nbPerType=tmpb.retn();
6061   return tmpa.retn();
6062 }
6063
6064 /*!
6065  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6066  *
6067  * \return a new object containing the old to new correspondence.
6068  *
6069  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6070  */
6071 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6072 {
6073   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6074 }
6075
6076 /*!
6077  * 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.
6078  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6079  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6080  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6081  */
6082 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6083 {
6084   DataArrayIdType *nbPerType=0;
6085   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6086   nbPerType->decrRef();
6087   return tmpa->buildPermArrPerLevel();
6088 }
6089
6090 /*!
6091  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6092  * The number of cells remains unchanged after the call of this method.
6093  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6094  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6095  *
6096  * \return the array giving the correspondence old to new.
6097  */
6098 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6099 {
6100   checkFullyDefined();
6101   computeTypes();
6102   const mcIdType *conn=_nodal_connec->begin();
6103   const mcIdType *connI=_nodal_connec_index->begin();
6104   mcIdType nbOfCells=getNumberOfCells();
6105   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6106   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6107     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6108       {
6109         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6110         types.push_back(curType);
6111         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6112       }
6113   DataArrayIdType *ret=DataArrayIdType::New();
6114   ret->alloc(nbOfCells,1);
6115   mcIdType *retPtr=ret->getPointer();
6116   std::fill(retPtr,retPtr+nbOfCells,-1);
6117   mcIdType newCellId=0;
6118   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6119     {
6120       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6121         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6122           retPtr[std::distance(connI,i)]=newCellId++;
6123     }
6124   renumberCells(retPtr,false);
6125   return ret;
6126 }
6127
6128 /*!
6129  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6130  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6131  * This method makes asumption that connectivity is correctly set before calling.
6132  */
6133 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6134 {
6135   checkConnectivityFullyDefined();
6136   const mcIdType *conn=_nodal_connec->begin();
6137   const mcIdType *connI=_nodal_connec_index->begin();
6138   mcIdType nbOfCells=getNumberOfCells();
6139   std::vector<MEDCouplingUMesh *> ret;
6140   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6141     {
6142       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6143       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6144       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6145       mcIdType endCellId=ToIdType(std::distance(connI,i));
6146       mcIdType sz=endCellId-beginCellId;
6147       mcIdType *cells=new mcIdType[sz];
6148       for(mcIdType j=0;j<sz;j++)
6149         cells[j]=beginCellId+j;
6150       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6151       delete [] cells;
6152       ret.push_back(m);
6153     }
6154   return ret;
6155 }
6156
6157 /*!
6158  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6159  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6160  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6161  *
6162  * \return a newly allocated instance, that the caller must manage.
6163  * \throw If \a this contains more than one geometric type.
6164  * \throw If the nodal connectivity of \a this is not fully defined.
6165  * \throw If the internal data is not coherent.
6166  */
6167 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6168 {
6169   checkConnectivityFullyDefined();
6170   if(_types.size()!=1)
6171     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6172   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6173   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6174   ret->setCoords(getCoords());
6175   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6176   if(retC)
6177     {
6178       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6179       retC->setNodalConnectivity(c);
6180     }
6181   else
6182     {
6183       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6184       if(!retD)
6185         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6186       DataArrayIdType *c=0,*ci=0;
6187       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6188       MCAuto<DataArrayIdType> cs(c),cis(ci);
6189       retD->setNodalConnectivity(cs,cis);
6190     }
6191   return ret.retn();
6192 }
6193
6194 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6195 {
6196   checkConnectivityFullyDefined();
6197   if(_types.size()!=1)
6198     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6199   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6200   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6201   if(cm.isDynamic())
6202     {
6203       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6204       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6205       throw INTERP_KERNEL::Exception(oss.str());
6206     }
6207   mcIdType nbCells=getNumberOfCells();
6208   mcIdType typi=ToIdType(typ);
6209   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6210   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6211   mcIdType *outPtr=connOut->getPointer();
6212   const mcIdType *conn=_nodal_connec->begin();
6213   const mcIdType *connI=_nodal_connec_index->begin();
6214   nbNodesPerCell++;
6215   for(mcIdType i=0;i<nbCells;i++,connI++)
6216     {
6217       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6218         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6219       else
6220         {
6221           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 << ") !";
6222           throw INTERP_KERNEL::Exception(oss.str());
6223         }
6224     }
6225   return connOut.retn();
6226 }
6227
6228 /*!
6229  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6230  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6231  * \param nodalConn nodal connectivity
6232  * \param nodalConnIndex nodal connectivity indices
6233  */
6234 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6235 {
6236   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6237   checkConnectivityFullyDefined();
6238   if(_types.size()!=1)
6239     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6240   mcIdType nbCells=getNumberOfCells(),
6241            lgth=_nodal_connec->getNumberOfTuples();
6242   if(lgth<nbCells)
6243     throw INTERP_KERNEL::Exception(msg0);
6244   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6245   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6246   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6247   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6248   cip[0]=0;
6249   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6250     {
6251       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6252       mcIdType delta(stop-strt);
6253       if(delta>=1)
6254         {
6255           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6256             cp=std::copy(incp+strt,incp+stop,cp);
6257           else
6258             throw INTERP_KERNEL::Exception(msg0);
6259         }
6260       else
6261         throw INTERP_KERNEL::Exception(msg0);
6262       cip[1]=cip[0]+delta;
6263     }
6264   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6265 }
6266
6267 /*!
6268  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6269  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6270  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6271  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6272  * are not used here to avoid the build of big permutation array.
6273  *
6274  * \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
6275  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6276  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6277  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6278  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6279  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6280  * \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
6281  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6282  */
6283 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6284                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6285                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6286 {
6287   std::vector<const MEDCouplingUMesh *> ms2;
6288   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6289     if(*it)
6290       {
6291         (*it)->checkConnectivityFullyDefined();
6292         ms2.push_back(*it);
6293       }
6294   if(ms2.empty())
6295     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6296   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6297   int meshDim=ms2[0]->getMeshDimension();
6298   std::vector<const MEDCouplingUMesh *> m1ssm;
6299   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6300   //
6301   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6302   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6303   mcIdType fake=0,rk=0;
6304   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6305   ret1->alloc(0,1); ret2->alloc(0,1);
6306   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6307     {
6308       if(meshDim!=(*it)->getMeshDimension())
6309         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6310       if(refCoo!=(*it)->getCoords())
6311         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6312       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6313       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6314       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6315       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6316         {
6317           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6318           m1ssmSingleAuto.push_back(singleCell);
6319           m1ssmSingle.push_back(singleCell);
6320           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6321         }
6322     }
6323   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6324   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6325   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6326   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6327     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6328   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6329   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6330   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6331   return ret0.retn();
6332 }
6333
6334 /*!
6335  * This method returns a newly created DataArrayIdType instance.
6336  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6337  */
6338 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6339 {
6340   checkFullyDefined();
6341   const mcIdType *conn=_nodal_connec->begin();
6342   const mcIdType *connIndex=_nodal_connec_index->begin();
6343   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6344   for(const mcIdType *w=begin;w!=end;w++)
6345     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6346       ret->pushBackSilent(*w);
6347   return ret.retn();
6348 }
6349
6350 /*!
6351  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6352  * are in [0:getNumberOfCells())
6353  */
6354 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6355 {
6356   checkFullyDefined();
6357   const mcIdType *conn=_nodal_connec->begin();
6358   const mcIdType *connI=_nodal_connec_index->begin();
6359   mcIdType nbOfCells=getNumberOfCells();
6360   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6361   mcIdType *tmp=new mcIdType[nbOfCells];
6362   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6363     {
6364       mcIdType j=0;
6365       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6366         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6367           tmp[std::distance(connI,i)]=j++;
6368     }
6369   DataArrayIdType *ret=DataArrayIdType::New();
6370   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6371   ret->copyStringInfoFrom(*da);
6372   mcIdType *retPtr=ret->getPointer();
6373   const mcIdType *daPtr=da->begin();
6374   mcIdType nbOfElems=da->getNbOfElems();
6375   for(mcIdType k=0;k<nbOfElems;k++)
6376     retPtr[k]=tmp[daPtr[k]];
6377   delete [] tmp;
6378   return ret;
6379 }
6380
6381 /*!
6382  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6383  * This method \b works \b for mesh sorted by type.
6384  * cells whose ids is in 'idsPerGeoType' array.
6385  * This method conserves coords and name of mesh.
6386  */
6387 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6388 {
6389   std::vector<mcIdType> code=getDistributionOfTypes();
6390   std::size_t nOfTypesInThis=code.size()/3;
6391   mcIdType sz=0,szOfType=0;
6392   for(std::size_t i=0;i<nOfTypesInThis;i++)
6393     {
6394       if(code[3*i]!=type)
6395         sz+=code[3*i+1];
6396       else
6397         szOfType=code[3*i+1];
6398     }
6399   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6400     if(*work<0 || *work>=szOfType)
6401       {
6402         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6403         oss << ". It should be in [0," << szOfType << ") !";
6404         throw INTERP_KERNEL::Exception(oss.str());
6405       }
6406   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6407   mcIdType *idsPtr=idsTokeep->getPointer();
6408   mcIdType offset=0;
6409   for(std::size_t i=0;i<nOfTypesInThis;i++)
6410     {
6411       if(code[3*i]!=type)
6412         for(mcIdType j=0;j<code[3*i+1];j++)
6413           *idsPtr++=offset+j;
6414       else
6415         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6416       offset+=code[3*i+1];
6417     }
6418   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6419   ret->copyTinyInfoFrom(this);
6420   return ret.retn();
6421 }
6422
6423 /*!
6424  * This method returns a vector of size 'this->getNumberOfCells()'.
6425  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6426  */
6427 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6428 {
6429   mcIdType ncell=getNumberOfCells();
6430   std::vector<bool> ret(ncell);
6431   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6432   const mcIdType *c=getNodalConnectivity()->begin();
6433   for(mcIdType i=0;i<ncell;i++)
6434     {
6435       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6436       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6437       ret[i]=cm.isQuadratic();
6438     }
6439   return ret;
6440 }
6441
6442 /*!
6443  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6444  */
6445 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6446 {
6447   if(other->getType()!=UNSTRUCTURED)
6448     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6449   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6450   return MergeUMeshes(this,otherC);
6451 }
6452
6453 /*!
6454  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6455  * computed by averaging coordinates of cell nodes, so this method is not a right
6456  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6457  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6458  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6459  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6460  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6461  *          components. The caller is to delete this array using decrRef() as it is
6462  *          no more needed.
6463  *  \throw If the coordinates array is not set.
6464  *  \throw If the nodal connectivity of cells is not defined.
6465  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6466  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6467  */
6468 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6469 {
6470   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6471   int spaceDim=getSpaceDimension();
6472   mcIdType nbOfCells=getNumberOfCells();
6473   ret->alloc(nbOfCells,spaceDim);
6474   ret->copyStringInfoFrom(*getCoords());
6475   double *ptToFill=ret->getPointer();
6476   const mcIdType *nodal=_nodal_connec->begin();
6477   const mcIdType *nodalI=_nodal_connec_index->begin();
6478   const double *coor=_coords->begin();
6479   for(mcIdType i=0;i<nbOfCells;i++)
6480     {
6481       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6482       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6483       ptToFill+=spaceDim;
6484     }
6485   return ret.retn();
6486 }
6487
6488
6489 /*!
6490  * See computeCellCenterOfMass().
6491  *  \param eps a precision for the detection of degenerated arc of circles.
6492  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6493  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6494  *          components. The caller is to delete this array using decrRef() as it is
6495  *          no more needed.
6496  *  \throw If the coordinates array is not set.
6497  *  \throw If the nodal connectivity of cells is not defined.
6498  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6499  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6500  */
6501 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6502 {
6503   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6504   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6505   return ret.retn();
6506 }
6507
6508
6509 /*!
6510  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6511  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6512  *
6513  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6514  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6515  *
6516  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6517  * \throw If \a this is not fully defined (coordinates and connectivity)
6518  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6519  */
6520 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6521 {
6522   checkFullyDefined();
6523   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6524   int spaceDim=getSpaceDimension();
6525   mcIdType nbOfCells=getNumberOfCells();
6526   mcIdType nbOfNodes=getNumberOfNodes();
6527   ret->alloc(nbOfCells,spaceDim);
6528   double *ptToFill=ret->getPointer();
6529   const mcIdType *nodal=_nodal_connec->begin();
6530   const mcIdType *nodalI=_nodal_connec_index->begin();
6531   const double *coor=_coords->begin();
6532   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6533     {
6534       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6535       std::fill(ptToFill,ptToFill+spaceDim,0.);
6536       if(type!=INTERP_KERNEL::NORM_POLYHED)
6537         {
6538           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6539             {
6540               if(*conn>=0 && *conn<nbOfNodes)
6541                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6542               else
6543                 {
6544                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6545                   throw INTERP_KERNEL::Exception(oss.str());
6546                 }
6547             }
6548           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6549           if(nbOfNodesInCell>0)
6550             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6551           else
6552             {
6553               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6554               throw INTERP_KERNEL::Exception(oss.str());
6555             }
6556         }
6557       else
6558         {
6559           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6560           s.erase(-1);
6561           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6562             {
6563               if(*it>=0 && *it<nbOfNodes)
6564                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6565               else
6566                 {
6567                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6568                   throw INTERP_KERNEL::Exception(oss.str());
6569                 }
6570             }
6571           if(!s.empty())
6572             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6573           else
6574             {
6575               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6576               throw INTERP_KERNEL::Exception(oss.str());
6577             }
6578         }
6579     }
6580   return ret.retn();
6581 }
6582
6583 /*!
6584  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6585  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6586  * are specified via an array of cell ids.
6587  *  \warning Validity of the specified cell ids is not checked!
6588  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6589  *  \param [in] begin - an array of cell ids of interest.
6590  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6591  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6592  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6593  *          caller is to delete this array using decrRef() as it is no more needed.
6594  *  \throw If the coordinates array is not set.
6595  *  \throw If the nodal connectivity of cells is not defined.
6596  *
6597  *  \if ENABLE_EXAMPLES
6598  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6599  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6600  *  \endif
6601  */
6602 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6603 {
6604   DataArrayDouble *ret=DataArrayDouble::New();
6605   int spaceDim=getSpaceDimension();
6606   std::size_t nbOfTuple=std::distance(begin,end);
6607   ret->alloc(nbOfTuple,spaceDim);
6608   double *ptToFill=ret->getPointer();
6609   double *tmp=new double[spaceDim];
6610   const mcIdType *nodal=_nodal_connec->begin();
6611   const mcIdType *nodalI=_nodal_connec_index->begin();
6612   const double *coor=_coords->begin();
6613   for(const mcIdType *w=begin;w!=end;w++)
6614     {
6615       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6616       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6617       ptToFill+=spaceDim;
6618     }
6619   delete [] tmp;
6620   return ret;
6621 }
6622
6623 /*!
6624  * 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".
6625  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6626  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6627  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6628  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6629  *
6630  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6631  * \throw If spaceDim!=3 or meshDim!=2.
6632  * \throw If connectivity of \a this is invalid.
6633  * \throw If connectivity of a cell in \a this points to an invalid node.
6634  */
6635 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6636 {
6637   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6638   mcIdType nbOfCells=getNumberOfCells();
6639   mcIdType nbOfNodes(getNumberOfNodes());
6640   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6641     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6642   ret->alloc(nbOfCells,4);
6643   double *retPtr(ret->getPointer());
6644   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6645   const double *coor(_coords->begin());
6646   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6647     {
6648       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6649       if(nodalI[1]-nodalI[0]>=4)
6650         {
6651           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6652                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6653                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6654           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6655                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6656                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6657           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]};
6658           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]));
6659           for(int j=0;j<3;j++)
6660             {
6661               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6662               if(nodeId>=0 && nodeId<nbOfNodes)
6663                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6664               else
6665                 {
6666                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6667                   throw INTERP_KERNEL::Exception(oss.str());
6668                 }
6669             }
6670           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6671             {
6672               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6673               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6674             }
6675           else
6676             {
6677               if(nodalI[1]-nodalI[0]==4)
6678                 {
6679                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6680                   throw INTERP_KERNEL::Exception(oss.str());
6681                 }
6682               //
6683               double dd[3]={0.,0.,0.};
6684               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6685                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6686               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6687               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6688               std::copy(dd,dd+3,matrix+4*2);
6689               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6690               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6691             }
6692         }
6693       else
6694         {
6695           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6696           throw INTERP_KERNEL::Exception(oss.str());
6697         }
6698     }
6699   return ret.retn();
6700 }
6701
6702 /*!
6703  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6704  *
6705  */
6706 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6707 {
6708   if(!da)
6709     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6710   da->checkAllocated();
6711   std::string name(da->getName());
6712   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6713   if(name.empty())
6714     ret->setName("Mesh");
6715   ret->setCoords(da);
6716   mcIdType nbOfTuples(da->getNumberOfTuples());
6717   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6718   c->alloc(2*nbOfTuples,1);
6719   cI->alloc(nbOfTuples+1,1);
6720   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6721   *cip++=0;
6722   for(mcIdType i=0;i<nbOfTuples;i++)
6723     {
6724       *cp++=INTERP_KERNEL::NORM_POINT1;
6725       *cp++=i;
6726       *cip++=2*(i+1);
6727     }
6728   ret->setConnectivity(c,cI,true);
6729   return ret.retn();
6730 }
6731
6732 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6733 {
6734   if(!da)
6735     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6736   da->checkAllocated();
6737   std::string name(da->getName());
6738   MCAuto<MEDCouplingUMesh> ret;
6739   {
6740     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6741     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6742     arr->alloc(da->getNumberOfTuples());
6743     tmp->setCoordsAt(0,arr);
6744     ret=tmp->buildUnstructured();
6745   }
6746   ret->setCoords(da);
6747   if(name.empty())
6748     ret->setName("Mesh");
6749   else
6750     ret->setName(name);
6751   return ret;
6752 }
6753
6754 /*!
6755  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6756  * Cells and nodes of
6757  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6758  *  \param [in] mesh1 - the first mesh.
6759  *  \param [in] mesh2 - the second mesh.
6760  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6761  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6762  *          is no more needed.
6763  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6764  *  \throw If the coordinates array is not set in none of the meshes.
6765  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6766  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6767  */
6768 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6769 {
6770   std::vector<const MEDCouplingUMesh *> tmp(2);
6771   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6772   return MergeUMeshes(tmp);
6773 }
6774
6775 /*!
6776  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6777  * Cells and nodes of
6778  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6779  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6780  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6781  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6782  *          is no more needed.
6783  *  \throw If \a a.size() == 0.
6784  *  \throw If \a a[ *i* ] == NULL.
6785  *  \throw If the coordinates array is not set in none of the meshes.
6786  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6787  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6788  */
6789 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6790 {
6791   std::size_t sz=a.size();
6792   if(sz==0)
6793     return MergeUMeshesLL(a);
6794   for(std::size_t ii=0;ii<sz;ii++)
6795     if(!a[ii])
6796       {
6797         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6798         throw INTERP_KERNEL::Exception(oss.str());
6799       }
6800   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6801   std::vector< const MEDCouplingUMesh * > aa(sz);
6802   int spaceDim=-3;
6803   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6804     {
6805       const MEDCouplingUMesh *cur=a[i];
6806       const DataArrayDouble *coo=cur->getCoords();
6807       if(coo)
6808         spaceDim=int(coo->getNumberOfComponents());
6809     }
6810   if(spaceDim==-3)
6811     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6812   for(std::size_t i=0;i<sz;i++)
6813     {
6814       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6815       aa[i]=bb[i];
6816     }
6817   return MergeUMeshesLL(aa);
6818 }
6819
6820 /*!
6821  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6822  * dimension and sharing the node coordinates array.
6823  * All cells of the first mesh precede all cells of the second mesh
6824  * within the result mesh.
6825  *  \param [in] mesh1 - the first mesh.
6826  *  \param [in] mesh2 - the second mesh.
6827  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6828  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6829  *          is no more needed.
6830  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6831  *  \throw If the meshes do not share the node coordinates array.
6832  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6833  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6834  */
6835 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6836 {
6837   std::vector<const MEDCouplingUMesh *> tmp(2);
6838   tmp[0]=mesh1; tmp[1]=mesh2;
6839   return MergeUMeshesOnSameCoords(tmp);
6840 }
6841
6842 /*!
6843  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6844  * dimension and sharing the node coordinates array.
6845  * All cells of the *i*-th mesh precede all cells of the
6846  * (*i*+1)-th mesh within the result mesh.
6847  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6848  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6849  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6850  *          is no more needed.
6851  *  \throw If \a a.size() == 0.
6852  *  \throw If \a a[ *i* ] == NULL.
6853  *  \throw If the meshes do not share the node coordinates array.
6854  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6855  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6856  */
6857 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6858 {
6859   if(meshes.empty())
6860     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6861   for(std::size_t ii=0;ii<meshes.size();ii++)
6862     if(!meshes[ii])
6863       {
6864         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6865         throw INTERP_KERNEL::Exception(oss.str());
6866       }
6867   const DataArrayDouble *coords=meshes.front()->getCoords();
6868   int meshDim=meshes.front()->getMeshDimension();
6869   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6870   mcIdType meshLgth=0;
6871   mcIdType meshIndexLgth=0;
6872   for(;iter!=meshes.end();iter++)
6873     {
6874       if(coords!=(*iter)->getCoords())
6875         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6876       if(meshDim!=(*iter)->getMeshDimension())
6877         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6878       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6879       meshIndexLgth+=(*iter)->getNumberOfCells();
6880     }
6881   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6882   nodal->alloc(meshLgth,1);
6883   mcIdType *nodalPtr=nodal->getPointer();
6884   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6885   nodalIndex->alloc(meshIndexLgth+1,1);
6886   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6887   mcIdType offset=0;
6888   for(iter=meshes.begin();iter!=meshes.end();iter++)
6889     {
6890       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6891       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6892       mcIdType nbOfCells=(*iter)->getNumberOfCells();
6893       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6894       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6895       if(iter!=meshes.begin())
6896         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6897       else
6898         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6899       offset+=meshLgth2;
6900     }
6901   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6902   ret->setName("merge");
6903   ret->setMeshDimension(meshDim);
6904   ret->setConnectivity(nodal,nodalIndex,true);
6905   ret->setCoords(coords);
6906   return ret;
6907 }
6908
6909 /*!
6910  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6911  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6912  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6913  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6914  * New" mode are returned for each input mesh.
6915  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6916  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
6917  *          valid values [0,1,2], see zipConnectivityTraducer().
6918  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6919  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6920  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
6921  *          no more needed.
6922  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6923  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6924  *          is no more needed.
6925  *  \throw If \a meshes.size() == 0.
6926  *  \throw If \a meshes[ *i* ] == NULL.
6927  *  \throw If the meshes do not share the node coordinates array.
6928  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6929  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
6930  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6931  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
6932  */
6933 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6934 {
6935   //All checks are delegated to MergeUMeshesOnSameCoords
6936   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6937   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6938   corr.resize(meshes.size());
6939   std::size_t nbOfMeshes=meshes.size();
6940   mcIdType offset=0;
6941   const mcIdType *o2nPtr=o2n->begin();
6942   for(std::size_t i=0;i<nbOfMeshes;i++)
6943     {
6944       DataArrayIdType *tmp=DataArrayIdType::New();
6945       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6946       tmp->alloc(curNbOfCells,1);
6947       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6948       offset+=curNbOfCells;
6949       tmp->setName(meshes[i]->getName());
6950       corr[i]=tmp;
6951     }
6952   return ret.retn();
6953 }
6954
6955 /*!
6956  * Makes all given meshes share the nodal connectivity array. The common connectivity
6957  * array is created by concatenating the connectivity arrays of all given meshes. All
6958  * the given meshes must be of the same space dimension but dimension of cells **can
6959  * differ**. This method is particularly useful in MEDLoader context to build a \ref
6960  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6961  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6962  *  \param [in,out] meshes - a vector of meshes to update.
6963  *  \throw If any of \a meshes is NULL.
6964  *  \throw If the coordinates array is not set in any of \a meshes.
6965  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6966  *  \throw If \a meshes are of different space dimension.
6967  */
6968 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6969 {
6970   std::size_t sz=meshes.size();
6971   if(sz==0 || sz==1)
6972     return;
6973   std::vector< const DataArrayDouble * > coords(meshes.size());
6974   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6975   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6976     {
6977       if((*it))
6978         {
6979           (*it)->checkConnectivityFullyDefined();
6980           const DataArrayDouble *coo=(*it)->getCoords();
6981           if(coo)
6982             *it2=coo;
6983           else
6984             {
6985               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6986               oss << " has no coordinate array defined !";
6987               throw INTERP_KERNEL::Exception(oss.str());
6988             }
6989         }
6990       else
6991         {
6992           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6993           oss << " is null !";
6994           throw INTERP_KERNEL::Exception(oss.str());
6995         }
6996     }
6997   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6998   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6999   mcIdType offset=(*it)->getNumberOfNodes();
7000   (*it++)->setCoords(res);
7001   for(;it!=meshes.end();it++)
7002     {
7003       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7004       (*it)->setCoords(res);
7005       (*it)->shiftNodeNumbersInConn(offset);
7006       offset+=oldNumberOfNodes;
7007     }
7008 }
7009
7010 /*!
7011  * Merges nodes coincident with a given precision within all given meshes that share
7012  * the nodal connectivity array. The given meshes **can be of different** mesh
7013  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7014  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7015  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7016  *  \param [in,out] meshes - a vector of meshes to update.
7017  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7018  *  \throw If any of \a meshes is NULL.
7019  *  \throw If the \a meshes do not share the same node coordinates array.
7020  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7021  */
7022 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7023 {
7024   if(meshes.empty())
7025     return ;
7026   std::set<const DataArrayDouble *> s;
7027   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7028     {
7029       if(*it)
7030         s.insert((*it)->getCoords());
7031       else
7032         {
7033           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 !";
7034           throw INTERP_KERNEL::Exception(oss.str());
7035         }
7036     }
7037   if(s.size()!=1)
7038     {
7039       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 !";
7040       throw INTERP_KERNEL::Exception(oss.str());
7041     }
7042   const DataArrayDouble *coo=*(s.begin());
7043   if(!coo)
7044     return;
7045   //
7046   DataArrayIdType *comm,*commI;
7047   coo->findCommonTuples(eps,-1,comm,commI);
7048   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7049   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7050   mcIdType newNbOfNodes;
7051   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7052   if(oldNbOfNodes==newNbOfNodes)
7053     return ;
7054   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7055   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7056     {
7057       (*it)->renumberNodesInConn(o2n->begin());
7058       (*it)->setCoords(newCoords);
7059     }
7060 }
7061
7062
7063 /*!
7064  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7065  */
7066 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7067 {
7068   std::size_t i, ip1;
7069   double v[3]={0.,0.,0.};
7070   std::size_t sz=std::distance(begin,end);
7071   if(!isQuadratic)
7072     for(i=0;i<sz;i++)
7073       {
7074         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7075         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7076         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];
7077         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7078         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7079       }
7080   else
7081     {
7082       // Same algorithm as above but also using intermediate quadratic points.
7083       // (taking only linear points might lead to issues if the linearized version of the
7084       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7085       std::size_t hsz = sz/2;
7086       for(std::size_t j=0;j<sz;j++)
7087         {
7088           if (j%2)  // current point i is quadratic, next point i+1 is standard
7089             {
7090               i = hsz+(j-1)/2;
7091               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7092             }
7093           else      // current point i is standard, next point i+1 is quadratic
7094             {
7095               i = j/2;
7096               ip1 = j/2+hsz;
7097             }
7098           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7099           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7100           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7101         }
7102     }
7103   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7104   return (ret>0.);
7105 }
7106
7107 /*!
7108  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7109  */
7110 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7111 {
7112   std::vector<std::pair<mcIdType,mcIdType> > edges;
7113   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7114   const mcIdType *bgFace=begin;
7115   for(std::size_t i=0;i<nbOfFaces;i++)
7116     {
7117       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7118       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7119       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7120         {
7121           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7122           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7123             return false;
7124           edges.push_back(p1);
7125         }
7126       bgFace=endFace+1;
7127     }
7128   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7129 }
7130
7131 /*!
7132  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7133  */
7134 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7135 {
7136   double vec0[3],vec1[3];
7137   std::size_t sz=std::distance(begin,end);
7138   if(sz%2!=0)
7139     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7140   mcIdType nbOfNodes=ToIdType(sz/2);
7141   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7142   const double *pt0=coords+3*begin[0];
7143   const double *pt1=coords+3*begin[nbOfNodes];
7144   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7145   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7146 }
7147
7148 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7149 {
7150   std::size_t sz=std::distance(begin,end);
7151   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7152   std::size_t nbOfNodes(sz/2);
7153   std::copy(begin,end,(mcIdType *)tmp);
7154   for(std::size_t j=1;j<nbOfNodes;j++)
7155     {
7156       begin[j]=tmp[nbOfNodes-j];
7157       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7158     }
7159 }
7160
7161 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7162 {
7163   std::size_t sz=std::distance(begin,end);
7164   if(sz!=4)
7165     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7166   double vec0[3],vec1[3];
7167   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7168   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];
7169   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;
7170 }
7171
7172 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7173 {
7174   std::size_t sz=std::distance(begin,end);
7175   if(sz!=5)
7176     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7177   double vec0[3];
7178   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7179   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7180   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7181 }
7182
7183 /*!
7184  * 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 )
7185  * 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
7186  * a 2D space.
7187  *
7188  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7189  * \param [in] coords the coordinates with nb of components exactly equal to 3
7190  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7191  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7192  */
7193 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7194                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7195 {
7196   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7197   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7198   double *vPtr=v->getPointer();
7199   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7200   double *pPtr=p->getPointer();
7201   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7202   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7203   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7204     {
7205       mcIdType face = e_f[e_fi[index] + i];
7206       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7207       // to differentiate faces going to different cells:
7208       pPtr++, *pPtr = 0;
7209       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7210         *pPtr += FromIdType<double>(f_e[j]);
7211     }
7212   pPtr=p->getPointer(); vPtr=v->getPointer();
7213   DataArrayIdType *comm1=0,*commI1=0;
7214   v->findCommonTuples(eps,-1,comm1,commI1);
7215   for (mcIdType i = 0; i < nbFaces; i++)
7216     if (comm1->findIdFirstEqual(i) < 0)
7217       {
7218         comm1->pushBackSilent(i);
7219         commI1->pushBackSilent(comm1->getNumberOfTuples());
7220       }
7221   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7222   const mcIdType *comm1Ptr=comm1->begin();
7223   const mcIdType *commI1Ptr=commI1->begin();
7224   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7225   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7226   //
7227   for(mcIdType i=0;i<nbOfGrps1;i++)
7228     {
7229       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7230       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7231       DataArrayIdType *comm2=0,*commI2=0;
7232       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7233       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7234         if (comm2->findIdFirstEqual(j) < 0)
7235           {
7236             comm2->pushBackSilent(j);
7237             commI2->pushBackSilent(comm2->getNumberOfTuples());
7238           }
7239       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7240       const mcIdType *comm2Ptr=comm2->begin();
7241       const mcIdType *commI2Ptr=commI2->begin();
7242       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7243       for(mcIdType j=0;j<nbOfGrps2;j++)
7244         {
7245           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7246             {
7247               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7248               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7249               res->pushBackSilent(-1);
7250             }
7251           else
7252             {
7253               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7254               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7255               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7256               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7257               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7258               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7259               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7260               const mcIdType *idsNodePtr=idsNode->begin();
7261               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];
7262               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7263               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7264               if(std::abs(norm)>eps)
7265                 {
7266                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7267                   mm3->rotate(center,vec,angle);
7268                 }
7269               mm3->changeSpaceDimension(2);
7270               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7271               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7272               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7273               mcIdType nbOfCells=mm4->getNumberOfCells();
7274               for(mcIdType k=0;k<nbOfCells;k++)
7275                 {
7276                   int l=0;
7277                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7278                     res->pushBackSilent(idsNodePtr[*work]);
7279                   res->pushBackSilent(-1);
7280                 }
7281             }
7282         }
7283     }
7284   res->popBackSilent();
7285 }
7286
7287 /*!
7288  * 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
7289  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7290  *
7291  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7292  * \param [in] coords coordinates expected to have 3 components.
7293  * \param [in] begin start of the nodal connectivity of the face.
7294  * \param [in] end end of the nodal connectivity (excluded) of the face.
7295  * \param [out] v the normalized vector of size 3
7296  * \param [out] p the pos of plane
7297  */
7298 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7299 {
7300   std::size_t nbPoints=std::distance(begin,end);
7301   if(nbPoints<3)
7302     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7303   double vec[3]={0.,0.,0.};
7304   std::size_t j=0;
7305   bool refFound=false;
7306   for(;j<nbPoints-1 && !refFound;j++)
7307     {
7308       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7309       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7310       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7311       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7312       if(norm>eps)
7313         {
7314           refFound=true;
7315           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7316         }
7317     }
7318   for(std::size_t i=j;i<nbPoints-1;i++)
7319     {
7320       double curVec[3];
7321       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7322       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7323       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7324       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7325       if(norm<eps)
7326         continue;
7327       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7328       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];
7329       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7330       if(norm>eps)
7331         {
7332           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7333           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7334           return ;
7335         }
7336     }
7337   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7338 }
7339
7340 /*!
7341  * This method tries to obtain a well oriented polyhedron.
7342  * If the algorithm fails, an exception will be thrown.
7343  */
7344 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7345 {
7346   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7347   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7348   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7349   isPerm[0]=true;
7350   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7351   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7352   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7353   //
7354   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7355     {
7356       bgFace=begin;
7357       std::size_t smthChanged=0;
7358       for(std::size_t i=0;i<nbOfFaces;i++)
7359         {
7360           endFace=std::find(bgFace+1,end,-1);
7361           nbOfEdgesInFace=std::distance(bgFace,endFace);
7362           if(!isPerm[i])
7363             {
7364               bool b=false;
7365               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7366                 {
7367                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7368                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7369                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7370                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7371                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7372                 }
7373               if(isPerm[i])
7374                 {
7375                   if(!b)
7376                     std::reverse(bgFace+1,endFace);
7377                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7378                     {
7379                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7380                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7381                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7382                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7383                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7384                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7385                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7386                       if(it!=edgesOK.end())
7387                         {
7388                           edgesOK.erase(it);
7389                           edgesFinished.push_back(p1);
7390                         }
7391                       else
7392                         edgesOK.push_back(p1);
7393                     }
7394                 }
7395             }
7396           bgFace=endFace+1;
7397         }
7398       if(smthChanged==0)
7399         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7400     }
7401   if(!edgesOK.empty())
7402     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7403   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7404     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7405       bgFace=begin;
7406       for(std::size_t i=0;i<nbOfFaces;i++)
7407         {
7408           endFace=std::find(bgFace+1,end,-1);
7409           std::reverse(bgFace+1,endFace);
7410           bgFace=endFace+1;
7411         }
7412     }
7413 }
7414
7415
7416 /*!
7417  * This method makes the assumption spacedimension == meshdimension == 2.
7418  * This method works only for linear cells.
7419  *
7420  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7421  */
7422 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7423 {
7424   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7425     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7426   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7427   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7428   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7429   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7430   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7431   mcIdType nbCells=skin->getNumberOfCells();
7432   if(nbCells==nbOfNodesExpected)
7433     return buildUnionOf2DMeshLinear(skin,n2o);
7434   else if(2*nbCells==nbOfNodesExpected)
7435     return buildUnionOf2DMeshQuadratic(skin,n2o);
7436   else
7437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7438 }
7439
7440 /*!
7441  * This method makes the assumption spacedimension == meshdimension == 3.
7442  * This method works only for linear cells.
7443  *
7444  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7445  */
7446 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7447 {
7448   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7449     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7450   MCAuto<MEDCouplingUMesh> m=computeSkin();
7451   const mcIdType *conn=m->getNodalConnectivity()->begin();
7452   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7453   mcIdType nbOfCells=m->getNumberOfCells();
7454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7455   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7456   if(nbOfCells<1)
7457     return ret.retn();
7458   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7459   for(mcIdType i=1;i<nbOfCells;i++)
7460     {
7461       *work++=-1;
7462       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7463     }
7464   return ret.retn();
7465 }
7466
7467 /*!
7468  * \brief Creates a graph of cell neighbors
7469  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7470  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7471  *  For example
7472  *  - index:  0 3 5 6 6
7473  *  - value:  1 2 3 2 3 3
7474  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7475  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7476  */
7477 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7478 {
7479   checkConnectivityFullyDefined();
7480
7481   int meshDim = this->getMeshDimension();
7482   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7483   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7484   this->getReverseNodalConnectivity(revConn,indexr);
7485   const mcIdType* indexr_ptr=indexr->begin();
7486   const mcIdType* revConn_ptr=revConn->begin();
7487
7488   const MEDCoupling::DataArrayIdType* index;
7489   const MEDCoupling::DataArrayIdType* conn;
7490   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7491   index=this->getNodalConnectivityIndex();
7492   mcIdType nbCells=this->getNumberOfCells();
7493   const mcIdType* index_ptr=index->begin();
7494   const mcIdType* conn_ptr=conn->begin();
7495
7496   //creating graph arcs (cell to cell relations)
7497   //arcs are stored in terms of (index,value) notation
7498   // 0 3 5 6 6
7499   // 1 2 3 2 3 3
7500   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7501   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7502
7503   //warning here one node have less than or equal effective number of cell with it
7504   //but cell could have more than effective nodes
7505   //because other equals nodes in other domain (with other global inode)
7506   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7507   std::vector <mcIdType> cell2cell;
7508   cell2cell.reserve(3*nbCells);
7509
7510   for (mcIdType icell=0; icell<nbCells;icell++)
7511     {
7512       std::map<mcIdType,mcIdType > counter;
7513       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7514         {
7515           mcIdType inode=conn_ptr[iconn];
7516           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7517             {
7518               mcIdType icell2=revConn_ptr[iconnr];
7519               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7520               if (iter!=counter.end()) (iter->second)++;
7521               else counter.insert(std::make_pair(icell2,1));
7522             }
7523         }
7524       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7525            iter!=counter.end(); iter++)
7526         if (iter->second >= meshDim)
7527           {
7528             cell2cell_index[icell+1]++;
7529             cell2cell.push_back(iter->first);
7530           }
7531     }
7532   indexr->decrRef();
7533   revConn->decrRef();
7534   cell2cell_index[0]=0;
7535   for (mcIdType icell=0; icell<nbCells;icell++)
7536     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7537
7538   //filling up index and value to create skylinearray structure
7539   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7540   return array;
7541 }
7542
7543
7544 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7545 {
7546   mcIdType nbOfCells=getNumberOfCells();
7547   if(nbOfCells<=0)
7548     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7549   ofs << "  <" << getVTKDataSetType() << ">\n";
7550   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7551   ofs << "      <PointData>\n" << pointData << std::endl;
7552   ofs << "      </PointData>\n";
7553   ofs << "      <CellData>\n" << cellData << std::endl;
7554   ofs << "      </CellData>\n";
7555   ofs << "      <Points>\n";
7556   if(getSpaceDimension()==3)
7557     _coords->writeVTK(ofs,8,"Points",byteData);
7558   else
7559     {
7560       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7561       coo->writeVTK(ofs,8,"Points",byteData);
7562     }
7563   ofs << "      </Points>\n";
7564   ofs << "      <Cells>\n";
7565   const mcIdType *cPtr=_nodal_connec->begin();
7566   const mcIdType *cIPtr=_nodal_connec_index->begin();
7567   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7568   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7569   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7570   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7571   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7572   mcIdType szFaceOffsets=0,szConn=0;
7573   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7574     {
7575       *w2=cPtr[cIPtr[i]];
7576       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7577         {
7578           *w1=-1;
7579           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7580           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7581         }
7582       else
7583         {
7584           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7585           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7586           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7587           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7588           w4=std::copy(c.begin(),c.end(),w4);
7589         }
7590     }
7591   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7592   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7593     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7594   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7595   types->writeVTK(ofs,8,"UInt8","types",byteData);
7596   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7597   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7598   if(szFaceOffsets!=0)
7599     {//presence of Polyhedra
7600       connectivity->reAlloc(szConn);
7601       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7602       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7603       w1=faces->getPointer();
7604       for(mcIdType i=0;i<nbOfCells;i++)
7605         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7606           {
7607             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7608             *w1++=nbFaces;
7609             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7610             for(mcIdType j=0;j<nbFaces;j++)
7611               {
7612                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7613                 *w1++=ToIdType(std::distance(w6,w5));
7614                 w1=std::copy(w6,w5,w1);
7615                 w6=w5+1;
7616               }
7617           }
7618       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7619     }
7620   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7621   ofs << "      </Cells>\n";
7622   ofs << "    </Piece>\n";
7623   ofs << "  </" << getVTKDataSetType() << ">\n";
7624 }
7625
7626 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7627 {
7628   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7629   if(_mesh_dim==-2)
7630     { stream << " Not set !"; return ; }
7631   stream << " Mesh dimension : " << _mesh_dim << ".";
7632   if(_mesh_dim==-1)
7633     return ;
7634   if(!_coords)
7635     { stream << " No coordinates set !"; return ; }
7636   if(!_coords->isAllocated())
7637     { stream << " Coordinates set but not allocated !"; return ; }
7638   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7639   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7640   if(!_nodal_connec_index)
7641     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7642   if(!_nodal_connec_index->isAllocated())
7643     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7644   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7645   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7646   if(cpt!=1 || lgth<1)
7647     return ;
7648   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7649 }
7650
7651 std::string MEDCouplingUMesh::getVTKDataSetType() const
7652 {
7653   return std::string("UnstructuredGrid");
7654 }
7655
7656 std::string MEDCouplingUMesh::getVTKFileExtension() const
7657 {
7658   return std::string("vtu");
7659 }
7660
7661
7662
7663 /**
7664  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7665  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7666  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7667  * The caller is to deal with the resulting DataArrayIdType.
7668  *  \throw If the coordinate array is not set.
7669  *  \throw If the nodal connectivity of the cells is not defined.
7670  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7671  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7672  *
7673  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7674  */
7675 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7676 {
7677   checkFullyDefined();
7678   if(getMeshDimension()!=1)
7679     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7680
7681   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7682   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7683   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7684   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7685   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7686   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7687   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7688   const mcIdType * dsi(_dsi->begin());
7689   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7690   m_points=0;
7691   if (dsii->getNumberOfTuples())
7692     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7693
7694   mcIdType nc=getNumberOfCells();
7695   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7696   result->alloc(nc,1);
7697
7698   // set of edges not used so far
7699   std::set<mcIdType> edgeSet;
7700   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7701
7702   mcIdType startSeg=0;
7703   mcIdType newIdx=0;
7704   // while we have points with only one neighbor segments
7705   do
7706     {
7707       std::list<mcIdType> linePiece;
7708       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7709       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7710         {
7711           // Fill the list forward (resp. backward) from the start segment:
7712           mcIdType activeSeg = startSeg;
7713           mcIdType prevPointId = -20;
7714           mcIdType ptId;
7715           while (!edgeSet.empty())
7716             {
7717               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7718                 {
7719                   if (direction==0)
7720                     linePiece.push_back(activeSeg);
7721                   else
7722                     linePiece.push_front(activeSeg);
7723                   edgeSet.erase(activeSeg);
7724                 }
7725
7726               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7727               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7728               if (dsi[ptId] == 1) // hitting the end of the line
7729                 break;
7730               prevPointId = ptId;
7731               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7732               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7733             }
7734         }
7735       // Done, save final piece into DA:
7736       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7737       newIdx += ToIdType(linePiece.size());
7738
7739       // identify next valid start segment (one which is not consumed)
7740       if(!edgeSet.empty())
7741         startSeg = *(edgeSet.begin());
7742     }
7743   while (!edgeSet.empty());
7744   return result.retn();
7745 }
7746
7747 /**
7748  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7749  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7750  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7751  * a minimal creation of new nodes is wanted.
7752  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7753  * nodes if a SEG3 is split without information of middle.
7754  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7755  * avoid to have a non conform mesh.
7756  *
7757  * \return mcIdType - the number of new nodes created (in most of cases 0).
7758  *
7759  * \throw If \a this is not coherent.
7760  * \throw If \a this has not spaceDim equal to 2.
7761  * \throw If \a this has not meshDim equal to 2.
7762  * \throw If some subcells needed to be split are orphan.
7763  * \sa MEDCouplingUMesh::conformize2D
7764  */
7765 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7766 {
7767   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7768     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7769   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7770   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7771     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7772   if(midOpt==0 && midOptI==0)
7773     {
7774       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7775       return 0;
7776     }
7777   else if(midOpt!=0 && midOptI!=0)
7778     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7779   else
7780     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7781 }
7782
7783 /*!
7784  * 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
7785  * 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
7786  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7787  * 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
7788  * 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.
7789  *
7790  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7791  */
7792 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7793 {
7794   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7795   if(sz>=4)
7796     {
7797       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7798       if(cm.getDimension()==2)
7799         {
7800           const mcIdType *node=nodalConnBg+1;
7801           mcIdType startNode=*node++;
7802           double refX=coords[2*startNode];
7803           for(;node!=nodalConnEnd;node++)
7804             {
7805               if(coords[2*(*node)]<refX)
7806                 {
7807                   startNode=*node;
7808                   refX=coords[2*startNode];
7809                 }
7810             }
7811           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7812           refX=1e300;
7813           double tmp1;
7814           double tmp2[2];
7815           double angle0=-M_PI/2;
7816           //
7817           mcIdType nextNode=-1;
7818           mcIdType prevNode=-1;
7819           double resRef;
7820           double angleNext=0.;
7821           while(nextNode!=startNode)
7822             {
7823               nextNode=-1;
7824               resRef=1e300;
7825               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7826                 {
7827                   if(*node!=tmpOut.back() && *node!=prevNode)
7828                     {
7829                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7830                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7831                       double res;
7832                       if(angleM<=angle0)
7833                         res=angle0-angleM;
7834                       else
7835                         res=angle0-angleM+2.*M_PI;
7836                       if(res<resRef)
7837                         {
7838                           nextNode=*node;
7839                           resRef=res;
7840                           angleNext=angleM;
7841                         }
7842                     }
7843                 }
7844               if(nextNode!=startNode)
7845                 {
7846                   angle0=angleNext-M_PI;
7847                   if(angle0<-M_PI)
7848                     angle0+=2*M_PI;
7849                   prevNode=tmpOut.back();
7850                   tmpOut.push_back(nextNode);
7851                 }
7852             }
7853           std::vector<mcIdType> tmp3(2*(sz-1));
7854           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7855           std::copy(nodalConnBg+1,nodalConnEnd,it);
7856           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7857             {
7858               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7859               return false;
7860             }
7861           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7862             {
7863               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7864               return false;
7865             }
7866           else
7867             {
7868               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7869               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7870               return true;
7871             }
7872         }
7873       else
7874         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7875     }
7876   else
7877     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7878 }
7879
7880 /*!
7881  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7882  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7883  * 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]].
7884  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7885  * A negative value in \b arrIn means that it is ignored.
7886  * 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.
7887  *
7888  * \param [in] arrIn arr origin array from which the extraction will be done.
7889  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7890  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7891  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7892  */
7893 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7894 {
7895   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7896   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7897 }
7898
7899 /*!
7900  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7901  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7902  * 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]].
7903  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7904  * A negative value in \b arrIn means that it is ignored.
7905  * 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.
7906  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7907  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7908  * \param [in] arrIn arr origin array from which the extraction will be done.
7909  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7910  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7911  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7912  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7913  * \sa MEDCouplingUMesh::partitionBySpreadZone
7914  */
7915 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7916 {
7917   nbOfDepthPeelingPerformed=0;
7918   if(!arrIndxIn)
7919     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7920   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7921   if(nbOfTuples<=0)
7922     {
7923       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7924       return ret;
7925     }
7926   //
7927   std::vector<bool> fetched(nbOfTuples,false);
7928   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7929 }
7930
7931
7932
7933 /*!
7934  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7935  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7936  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7937  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7938  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7939  *
7940  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7941  */
7942 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7943 {
7944   checkFullyDefined();
7945   int mdim=getMeshDimension();
7946   int spaceDim=getSpaceDimension();
7947   if(mdim!=spaceDim)
7948     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7949   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7950   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7951   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7952   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7953   ret->setCoords(getCoords());
7954   ret->allocateCells(ToIdType(partition.size()));
7955   //
7956   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7957     {
7958       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7959       MCAuto<DataArrayIdType> cell;
7960       switch(mdim)
7961       {
7962         case 2:
7963           cell=tmp->buildUnionOf2DMesh();
7964           break;
7965         case 3:
7966           cell=tmp->buildUnionOf3DMesh();
7967           break;
7968         default:
7969           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7970       }
7971
7972       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7973     }
7974   //
7975   ret->finishInsertingCells();
7976   return ret.retn();
7977 }
7978
7979 /*!
7980  * This method partitions \b this into contiguous zone.
7981  * This method only needs a well defined connectivity. Coordinates are not considered here.
7982  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7983  */
7984 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7985 {
7986   DataArrayIdType *neigh=0,*neighI=0;
7987   computeNeighborsOfCells(neigh,neighI);
7988   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7989   return PartitionBySpreadZone(neighAuto,neighIAuto);
7990 }
7991
7992 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7993 {
7994   if(!arrIn || !arrIndxIn)
7995     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7996   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7997   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
7998   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
7999     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8000   mcIdType nbOfCellsCur(nbOfTuples-1);
8001   std::vector<DataArrayIdType *> ret;
8002   if(nbOfCellsCur<=0)
8003     return ret;
8004   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8005   std::vector< MCAuto<DataArrayIdType> > ret2;
8006   mcIdType seed=0;
8007   while(seed<nbOfCellsCur)
8008     {
8009       mcIdType nbOfPeelPerformed=0;
8010       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8011       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8012     }
8013   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8014     ret.push_back((*it).retn());
8015   return ret;
8016 }
8017
8018 /*!
8019  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8020  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8021  *
8022  * \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.
8023  * \return a newly allocated DataArrayIdType to be managed by the caller.
8024  * \throw In case of \a code has not the right format (typically of size 3*n)
8025  */
8026 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8027 {
8028   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8029   std::size_t nb=code.size()/3;
8030   if(code.size()%3!=0)
8031     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8032   ret->alloc(nb,2);
8033   mcIdType *retPtr=ret->getPointer();
8034   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8035     {
8036       retPtr[0]=code[3*i+2];
8037       retPtr[1]=code[3*i+2]+code[3*i+1];
8038     }
8039   return ret.retn();
8040 }
8041
8042 /*!
8043  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8044  * All cells in \a this are expected to be linear 3D cells.
8045  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8046  * It leads to an increase to number of cells.
8047  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8048  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8049  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8050  *
8051  * \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.
8052  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8053  * \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.
8054  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8055  *          an id of old cell producing it. The caller is to delete this array using
8056  *         decrRef() as it is no more needed.
8057  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8058  *
8059  * \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
8060  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8061  *
8062  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8063  * \throw If \a this is not fully constituted with linear 3D cells.
8064  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8065  */
8066 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8067 {
8068   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8069   checkConnectivityFullyDefined();
8070   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8071     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8072   mcIdType nbOfCells=getNumberOfCells();
8073   mcIdType nbNodes(getNumberOfNodes());
8074   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8075   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8076   mcIdType *retPt(ret->getPointer());
8077   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8078   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8079   const mcIdType *oldc(_nodal_connec->begin());
8080   const mcIdType *oldci(_nodal_connec_index->begin());
8081   const double *coords(_coords->begin());
8082   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8083     {
8084       std::vector<mcIdType> a; std::vector<double> b;
8085       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8086       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8087       const mcIdType *aa(&a[0]);
8088       if(!b.empty())
8089         {
8090           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8091             if(*it<0)
8092               *it=(-(*(it))-1+nbNodes);
8093           addPts->insertAtTheEnd(b.begin(),b.end());
8094           nbNodes+=ToIdType(b.size()/3);
8095         }
8096       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8097         newConn->insertAtTheEnd(aa,aa+4);
8098     }
8099   if(!addPts->empty())
8100     {
8101       addPts->rearrange(3);
8102       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8103       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8104       ret0->setCoords(addPts);
8105     }
8106   else
8107     {
8108       nbOfAdditionalPoints=0;
8109       ret0->setCoords(getCoords());
8110     }
8111   ret0->setNodalConnectivity(newConn);
8112   //
8113   ret->computeOffsetsFull();
8114   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8115   return ret0.retn();
8116 }
8117
8118 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8119     _own_cell(true),_cell_id(-1),_nb_cell(0)
8120 {
8121   if(mesh)
8122     {
8123       mesh->incrRef();
8124       _nb_cell=mesh->getNumberOfCells();
8125     }
8126 }
8127
8128 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8129 {
8130   if(_mesh)
8131     _mesh->decrRef();
8132   if(_own_cell)
8133     delete _cell;
8134 }
8135
8136 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8137     _own_cell(false),_cell_id(bg-1),
8138     _nb_cell(end)
8139 {
8140   if(mesh)
8141     mesh->incrRef();
8142 }
8143
8144 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8145 {
8146   _cell_id++;
8147   if(_cell_id<_nb_cell)
8148     {
8149       _cell->next();
8150       return _cell;
8151     }
8152   else
8153     return 0;
8154 }
8155
8156 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8157 {
8158   if(_mesh)
8159     _mesh->incrRef();
8160 }
8161
8162 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8163 {
8164   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8165 }
8166
8167 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8168 {
8169   if(_mesh)
8170     _mesh->decrRef();
8171 }
8172
8173 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8174     _itc(itc),
8175     _bg(bg),_end(end)
8176 {
8177   if(_mesh)
8178     _mesh->incrRef();
8179 }
8180
8181 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8182 {
8183   if(_mesh)
8184     _mesh->decrRef();
8185 }
8186
8187 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8188 {
8189   return _type;
8190 }
8191
8192 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8193 {
8194   return _end-_bg;
8195 }
8196
8197 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8198 {
8199   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8200 }
8201
8202 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8203 {
8204   if(mesh)
8205     {
8206       mesh->incrRef();
8207       _nb_cell=mesh->getNumberOfCells();
8208     }
8209 }
8210
8211 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8212 {
8213   if(_mesh)
8214     _mesh->decrRef();
8215   delete _cell;
8216 }
8217
8218 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8219 {
8220   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8221   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8222   if(_cell_id<_nb_cell)
8223     {
8224       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8225       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8226       mcIdType startId=_cell_id;
8227       _cell_id+=nbOfElems;
8228       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8229     }
8230   else
8231     return 0;
8232 }
8233
8234 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8235 {
8236   if(mesh)
8237     {
8238       _conn=mesh->getNodalConnectivity()->getPointer();
8239       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8240     }
8241 }
8242
8243 void MEDCouplingUMeshCell::next()
8244 {
8245   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8246     {
8247       _conn+=_conn_lgth;
8248       _conn_indx++;
8249     }
8250   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8251 }
8252
8253 std::string MEDCouplingUMeshCell::repr() const
8254 {
8255   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8256     {
8257       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8258       oss << " : ";
8259       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8260       return oss.str();
8261     }
8262   else
8263     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8264 }
8265
8266 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8267 {
8268   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8269     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8270   else
8271     return INTERP_KERNEL::NORM_ERROR;
8272 }
8273
8274 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8275 {
8276   lgth=_conn_lgth;
8277   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8278     return _conn;
8279   else
8280     return 0;
8281 }