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