Salome HOME
[EDF27859] : Correct bug in case of HEXA/HEXA in P1P0 mode with PLANAR_FACE5 / PLANAR...
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \b WARNING: this method will not modify edges connectivity! Take a look at colinearizeEdges for that.
1344  *
1345  * \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
1346  *             precision.
1347  */
1348 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1349 {
1350   checkFullyDefined();
1351   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1352     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1353   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1354   coords->recenterForMaxPrecision(eps);
1355   //
1356   mcIdType nbOfCells=getNumberOfCells();
1357   const mcIdType *conn=_nodal_connec->getConstPointer();
1358   const mcIdType *index=_nodal_connec_index->getConstPointer();
1359   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1360   connINew->alloc(nbOfCells+1,1);
1361   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1362   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1363   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1364   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1365   bool changed=false;
1366   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1367     {
1368       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1369         {
1370           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1371           changed=true;
1372         }
1373       else
1374         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1375       *connINewPtr=connNew->getNumberOfTuples();
1376     }
1377   if(changed)
1378     setConnectivity(connNew,connINew,false);
1379 }
1380
1381 /*!
1382  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1383  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1384  * This method allows to simplify edges of polyhedron cells so that consecutive colinear segments (with intermediate points
1385  * not used by any other cell) are merged together.
1386  *
1387  * \param [in] eps is a relative precision that allows to establish if two consecutive 3D segments are colinear or not.
1388  *
1389  * \sa simplifyPolyhedra
1390  */
1391 void MEDCouplingUMesh::colinearizeEdges(double eps)
1392 {
1393   //
1394   // Thanks to Antoine Gerschenfeld (CEA) for contributing this method!
1395   //
1396   using DAI = MCAuto<DataArrayIdType>;
1397   checkFullyDefined();
1398   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1399     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearizeEdges() : works with meshdim=3 and spaceDim=3!");
1400   double seps = sqrt(1-eps);
1401   // Computing connectivities and correspondances : elements -> segments -> points
1402   DAI E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New()),
1403          F_Si(DataArrayIdType::New()), F_S(DataArrayIdType::New()), S_Fi(DataArrayIdType::New()), S_F(DataArrayIdType::New()),
1404          S_Pi(DataArrayIdType::New()), S_P(DataArrayIdType::New()), P_Si(DataArrayIdType::New()), P_S(DataArrayIdType::New());
1405   MCAuto<MEDCouplingUMesh> m_f(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei)),
1406          m_s(m_f->buildDescendingConnectivity(F_S, F_Si, S_F, S_Fi)),
1407          m_p(m_s->buildDescendingConnectivity(S_P, S_Pi, P_S, P_Si)); // E: elem, F: faces, S: segments (edges), P: points (vertices)
1408   const mcIdType *S_Pp(S_P->begin()), *S_Pip(S_Pi->begin()), *P_Sp(P_S->begin()), *P_Sip(P_Si->begin());
1409   std::set<mcIdType> pt_rem;
1410   const mcIdType *m_pi = m_p->getNodalConnectivityIndex()->begin(),
1411                  *m_pc = m_p->getNodalConnectivity()->begin();
1412   double (*coord)[3] = (double (*)[3]) getCoords()->begin();
1413   // Find all points only connected to exaclty 2 segments - they are the candidates for elimination
1414   // Note that in 3D this can only happen for polyhedrons (when this happens at all)
1415   DAI dsi = P_Si->deltaShiftIndex();
1416   DAI cand = dsi->findIdsEqual(2);
1417   for (const mcIdType& i: *cand)  // i is a point to be potentially eliminated, shared by 2 segs only
1418     {
1419       double n2[2] = {0., 0.}, scal = 0.; // n2 is a squared norm, scal is a scalar product
1420       mcIdType p[2][2];                   // p[j][k] is the ID (in the coord array) of the k-th point of the j-th segment
1421       for (mcIdType j = 0; j < 2; j++)
1422         for (mcIdType k = 0; k < 2; k++)
1423           {
1424             mcIdType off1 = P_Sip[i] + j;   // offset to get ID of the j-th seg (around the i-th point) in the point->seg correspondance
1425             mcIdType pt_id = P_Sp[off1] + k; // ID of the k-th point of the j-th seg in the point->seg correspondance
1426             mcIdType pt_id2 = S_Pp[S_Pip[pt_id]]; // ID of the point in the point mesh
1427             p[j][k] = m_pc[m_pi[pt_id2] + 1];  // Absolute ID, as read from the connectvity (+1 to skip type: NORM_POINT1)
1428             // Just for fun, as initially written by Antoine :-)
1429             // p[j][k] = m_pc[m_pi[S_P->getIJ(S_Pi->getIJ(P_S->getIJ(P_Si->getIJ(i, 0) + j, 0), 0) + k, 0)] + 1];
1430           }
1431       // Geometric test on scalar product
1432       for (int d = 0; d < 3; d++) // dimension
1433         {
1434           for (int j = 0; j < 2; j++)
1435             n2[j] += std::pow(coord[p[j][1]][d] - coord[p[j][0]][d], 2);
1436           scal += (coord[p[1][1]][d] - coord[p[1][0]][d]) * (coord[p[0][1]][d] - coord[p[0][0]][d]);
1437         }
1438       if (scal * scal > seps * n2[0] * n2[1]) // seps is a sqrt for homogeneity
1439         pt_rem.insert(m_pc[m_pi[i] + 1]);  // point should be removed
1440     }
1441   // Clean connectivity by filtering points to be removed:
1442   DataArrayIdType *old_index = getNodalConnectivityIndex(), *old_conn = getNodalConnectivity();
1443   DAI new_index(DataArrayIdType::New()), new_conn(DataArrayIdType::New());
1444   const mcIdType *old_index_p(old_index->begin()), *old_conn_p(old_conn->begin());
1445   for (mcIdType i = 0; i < getNumberOfCells(); i++)
1446     {
1447       new_index->pushBackSilent(new_conn->getNbOfElems());
1448       for (mcIdType j = old_index_p[i]; j < old_index_p[i + 1]; j++)
1449         {
1450           // Keep point if it is not to be removed, or if is first in connectivity (TODO this last check could be removed?)
1451           if (std::find(pt_rem.begin(), pt_rem.end(), old_conn_p[j]) == pt_rem.end() || j == old_index_p[i])
1452             new_conn->pushBackSilent(old_conn_p[j]);
1453         }
1454     }
1455   new_index->pushBackSilent(new_conn->getNbOfElems());
1456   setConnectivity(new_conn, new_index);
1457 }
1458
1459 /*!
1460  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1461  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1462  * the format of the returned DataArrayIdType instance.
1463  *
1464  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1465  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1466  */
1467 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1468 {
1469   checkConnectivityFullyDefined();
1470   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1471   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1472   std::vector<bool> retS(maxElt,false);
1473   computeNodeIdsAlg(retS);
1474   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1475 }
1476
1477 /*!
1478  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1479  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1480  */
1481 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1482 {
1483   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1484            nbOfCells=getNumberOfCells();
1485   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1486   for(mcIdType i=0;i<nbOfCells;i++)
1487     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1488       if(conn[j]>=0)
1489         {
1490           if(conn[j]<nbOfNodes)
1491             nodeIdsInUse[conn[j]]=true;
1492           else
1493             {
1494               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1495               throw INTERP_KERNEL::Exception(oss.str());
1496             }
1497         }
1498 }
1499
1500 /// @cond INTERNAL
1501
1502 struct MEDCouplingAccVisit
1503 {
1504   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1505   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1506   mcIdType _new_nb_of_nodes;
1507 };
1508
1509 /// @endcond
1510
1511 /*!
1512  * Finds nodes not used in any cell and returns an array giving a new id to every node
1513  * by excluding the unused nodes, for which the array holds -1. The result array is
1514  * a mapping in "Old to New" mode.
1515  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1516  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1517  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1518  *          if the node is unused or a new id else. The caller is to delete this
1519  *          array using decrRef() as it is no more needed.
1520  *  \throw If the coordinates array is not set.
1521  *  \throw If the nodal connectivity of cells is not defined.
1522  *  \throw If the nodal connectivity includes an invalid id.
1523  *
1524  *  \if ENABLE_EXAMPLES
1525  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1526  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1527  *  \endif
1528  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1529  */
1530 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1531 {
1532   nbrOfNodesInUse=-1;
1533   mcIdType nbOfNodes(getNumberOfNodes());
1534   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1535   ret->alloc(nbOfNodes,1);
1536   mcIdType *traducer=ret->getPointer();
1537   std::fill(traducer,traducer+nbOfNodes,-1);
1538   mcIdType nbOfCells=getNumberOfCells();
1539   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1540   const mcIdType *conn=_nodal_connec->getConstPointer();
1541   for(mcIdType i=0;i<nbOfCells;i++)
1542     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1543       if(conn[j]>=0)
1544         {
1545           if(conn[j]<nbOfNodes)
1546             traducer[conn[j]]=1;
1547           else
1548             {
1549               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1550               throw INTERP_KERNEL::Exception(oss.str());
1551             }
1552         }
1553   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1554   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1555   return ret.retn();
1556 }
1557
1558 /*!
1559  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1560  * For each cell in \b this the number of nodes constituting cell is computed.
1561  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1562  * So for pohyhedrons some nodes can be counted several times in the returned result.
1563  *
1564  * \return a newly allocated array
1565  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1566  */
1567 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1568 {
1569   checkConnectivityFullyDefined();
1570   mcIdType nbOfCells=getNumberOfCells();
1571   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1572   ret->alloc(nbOfCells,1);
1573   mcIdType *retPtr=ret->getPointer();
1574   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1575   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1576   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1577     {
1578       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1579         *retPtr=connI[i+1]-connI[i]-1;
1580       else
1581         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1582     }
1583   return ret.retn();
1584 }
1585
1586 /*!
1587  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1588  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1589  *
1590  * \return DataArrayIdType * - new object to be deallocated by the caller.
1591  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1592  */
1593 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1594 {
1595   checkConnectivityFullyDefined();
1596   mcIdType nbOfCells=getNumberOfCells();
1597   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1598   ret->alloc(nbOfCells,1);
1599   mcIdType *retPtr=ret->getPointer();
1600   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1601   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1602   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1603     {
1604       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1605       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1606         *retPtr=ToIdType(s.size());
1607       else
1608         {
1609           s.erase(-1);
1610           *retPtr=ToIdType(s.size());
1611         }
1612     }
1613   return ret.retn();
1614 }
1615
1616 /*!
1617  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1618  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1619  *
1620  * \return a newly allocated array
1621  */
1622 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1623 {
1624   checkConnectivityFullyDefined();
1625   mcIdType nbOfCells=getNumberOfCells();
1626   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1627   ret->alloc(nbOfCells,1);
1628   mcIdType *retPtr=ret->getPointer();
1629   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1630   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1631   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1632     {
1633       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1634       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1635     }
1636   return ret.retn();
1637 }
1638
1639 /*!
1640  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1641  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1642  * array mean that the corresponding old node is no more used.
1643  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1644  *           this->getNumberOfNodes() before call of this method. The caller is to
1645  *           delete this array using decrRef() as it is no more needed.
1646  *  \throw If the coordinates array is not set.
1647  *  \throw If the nodal connectivity of cells is not defined.
1648  *  \throw If the nodal connectivity includes an invalid id.
1649  *  \sa areAllNodesFetched
1650  *
1651  *  \if ENABLE_EXAMPLES
1652  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1653  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1654  *  \endif
1655  */
1656 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1657 {
1658   return MEDCouplingPointSet::zipCoordsTraducer();
1659 }
1660
1661 /*!
1662  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1663  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1664  */
1665 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1666 {
1667   switch(compType)
1668   {
1669     case 0:
1670       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1671     case 1:
1672       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1673     case 2:
1674       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1675     case 3:
1676       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1677     case 7:
1678       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1679   }
1680   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1681 }
1682
1683 /*!
1684  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1685  */
1686 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1687 {
1688   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1689     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1690   return 0;
1691 }
1692
1693 /*!
1694  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1695  */
1696 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1697 {
1698   mcIdType sz=connI[cell1+1]-connI[cell1];
1699   if(sz==connI[cell2+1]-connI[cell2])
1700     {
1701       if(conn[connI[cell1]]==conn[connI[cell2]])
1702         {
1703           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1704           unsigned dim=cm.getDimension();
1705           if(dim!=3)
1706             {
1707               if(dim!=1)
1708                 {
1709                   mcIdType sz1=2*(sz-1);
1710                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1711                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1712                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1713                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1714                   return work!=tmp+sz1?1:0;
1715                 }
1716               else
1717                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1718             }
1719           else
1720             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1721         }
1722     }
1723   return 0;
1724 }
1725
1726 /*!
1727  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1728  */
1729 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1730 {
1731   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1732     {
1733       if(conn[connI[cell1]]==conn[connI[cell2]])
1734         {
1735           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1736           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1737           return s1==s2?1:0;
1738         }
1739     }
1740   return 0;
1741 }
1742
1743 /*!
1744  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1745  */
1746 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1747 {
1748   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1749     {
1750       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1751       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1752       return s1==s2?1:0;
1753     }
1754   return 0;
1755 }
1756
1757 /*!
1758  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1759  */
1760 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1761 {
1762   mcIdType sz=connI[cell1+1]-connI[cell1];
1763   if(sz==connI[cell2+1]-connI[cell2])
1764     {
1765       if(conn[connI[cell1]]==conn[connI[cell2]])
1766         {
1767           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1768           unsigned dim=cm.getDimension();
1769           if(dim!=3)
1770             {
1771               if(dim!=1)
1772                 {
1773                   mcIdType sz1=2*(sz-1);
1774                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1775                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1776                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1777                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1778                   if(work!=tmp+sz1)
1779                     return 1;
1780                   else
1781                     {
1782                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1783                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1784                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1785                         return 2;
1786                       else
1787                         return 0;
1788                     }
1789                 }
1790               else
1791                 {//case of SEG2 and SEG3
1792                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1793                     return 1;
1794                   if(!cm.isQuadratic())
1795                     {
1796                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1797                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1798                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1799                         return 2;
1800                       return 0;
1801                     }
1802                   else
1803                     {
1804                       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])
1805                         return 2;
1806                       return 0;
1807                     }
1808                 }
1809             }
1810           else
1811             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1812         }
1813     }
1814   return 0;
1815 }
1816
1817
1818 /*!
1819  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1820  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1821  * 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.
1822  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1823  * This method is time consuming.
1824  *
1825  * \param [in] compType input specifying the technique used to compare cells each other.
1826  *   - 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.
1827  *   - 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)
1828  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1829  *   - 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
1830  * can be used for users not sensitive to orientation of cell
1831  * \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.
1832  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1833  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1834  *
1835  */
1836 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1837 {
1838   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1839   getReverseNodalConnectivity(revNodal,revNodalI);
1840   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1841 }
1842
1843 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1844                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1845 {
1846   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1847   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1848   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1849   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1850   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1851   std::vector<bool> isFetched(nbOfCells,false);
1852   if(startCellId==0)
1853     {
1854       for(mcIdType i=startCellId;i<nbOfCells;i++)
1855         {
1856           if(!isFetched[i])
1857             {
1858               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));
1859               std::vector<mcIdType> v,v2;
1860               if(connOfNode!=connPtr+connIPtr[i+1])
1861                 {
1862                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1863                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1864                   connOfNode++;
1865                 }
1866               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1867                 if(*connOfNode>=0)
1868                   {
1869                     v=v2;
1870                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1871                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1872                     v2.resize(std::distance(v2.begin(),it));
1873                   }
1874               if(v2.size()>1)
1875                 {
1876                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1877                     {
1878                       mcIdType pos=commonCellsI->back();
1879                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1880                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1881                         isFetched[*it]=true;
1882                     }
1883                 }
1884             }
1885         }
1886     }
1887   else
1888     {
1889       for(mcIdType i=startCellId;i<nbOfCells;i++)
1890         {
1891           if(!isFetched[i])
1892             {
1893               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));
1894               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1895               std::vector<mcIdType> v,v2;
1896               if(connOfNode!=connPtr+connIPtr[i+1])
1897                 {
1898                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1899                   connOfNode++;
1900                 }
1901               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1902                 if(*connOfNode>=0)
1903                   {
1904                     v=v2;
1905                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1906                     v2.resize(std::distance(v2.begin(),it));
1907                   }
1908               // v2 contains now candidates. Problem candidates are sorted using id rank.
1909               if(v2.size()>1)
1910                 {
1911                   if(v2[0]!=i)
1912                   {
1913                     auto it(std::find(v2.begin(),v2.end(),i));
1914                     std::swap(*v2.begin(),*it);
1915                   }
1916                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1917                     {
1918                       mcIdType newPos(commonCells->getNumberOfTuples());
1919                       mcIdType pos(commonCellsI->back());
1920                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1921                       commonCellsI->pushBackSilent(newPos);
1922                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1923                         isFetched[*it]=true;
1924                     }
1925                 }
1926             }
1927         }
1928     }
1929   commonCellsArr=commonCells.retn();
1930   commonCellsIArr=commonCellsI.retn();
1931 }
1932
1933 /*!
1934  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1935  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1936  * than \a this->getNumberOfCells() in the returned array means that there is no
1937  * corresponding cell in \a this mesh.
1938  * It is expected that \a this and \a other meshes share the same node coordinates
1939  * array, if it is not so an exception is thrown.
1940  *  \param [in] other - the mesh to compare with.
1941  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1942  *         valid values [0,1,2], see zipConnectivityTraducer().
1943  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1944  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1945  *         values. The caller is to delete this array using
1946  *         decrRef() as it is no more needed.
1947  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1948  *         mesh.
1949  *
1950  *  \if ENABLE_EXAMPLES
1951  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1952  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1953  *  \endif
1954  *  \sa checkDeepEquivalOnSameNodesWith()
1955  *  \sa checkGeoEquivalWith()
1956  */
1957 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1958 {
1959   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1960   mcIdType nbOfCells=getNumberOfCells();
1961   static const int possibleCompType[]={0,1,2};
1962   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1963     {
1964       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1965       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1966       oss << " !";
1967       throw INTERP_KERNEL::Exception(oss.str());
1968     }
1969   //
1970   if(other->getNumberOfCells()==0)
1971   {
1972     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1973     return true;
1974   }
1975   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1976   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1977   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1978   mcIdType newNbOfCells=-1;
1979   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1980   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1981   mcIdType maxPart(p0->getMaxValueInArray());
1982   bool ret(maxPart==newNbOfCells-1);
1983   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1984   // fill p1 array in case of presence of cells in other not in this
1985   mcIdType *pt(p1->getPointer());
1986   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1987     pt[i+1] = i+1;
1988   //
1989   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1990   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1991   arr = p2.retn();
1992   return ret;
1993 }
1994
1995 /*!
1996  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1997  * This method tries to determine if \b other is fully included in \b this.
1998  * The main difference is that this method is not expected to throw exception.
1999  * This method has two outputs :
2000  *
2001  * \param other other mesh
2002  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2003  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2004  */
2005 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
2006 {
2007   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2008   DataArrayIdType *commonCells=0,*commonCellsI=0;
2009   mcIdType thisNbCells=getNumberOfCells();
2010   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2011   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2012   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2013   mcIdType otherNbCells=other->getNumberOfCells();
2014   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
2015   arr2->alloc(otherNbCells,1);
2016   arr2->fillWithZero();
2017   mcIdType *arr2Ptr=arr2->getPointer();
2018   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2019   for(mcIdType i=0;i<nbOfCommon;i++)
2020     {
2021       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
2022       if(start<thisNbCells)
2023         {
2024           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2025             {
2026               mcIdType sig=commonCellsPtr[j]>0?1:-1;
2027               mcIdType val=std::abs(commonCellsPtr[j])-1;
2028               if(val>=thisNbCells)
2029                 arr2Ptr[val-thisNbCells]=sig*(start+1);
2030             }
2031         }
2032     }
2033   arr2->setName(other->getName());
2034   if(arr2->presenceOfValue(0))
2035     return false;
2036   arr=arr2.retn();
2037   return true;
2038 }
2039
2040 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2041 {
2042   if(!other)
2043     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2044   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2045   if(!otherC)
2046     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2047   std::vector<const MEDCouplingUMesh *> ms(2);
2048   ms[0]=this;
2049   ms[1]=otherC;
2050   return MergeUMeshesOnSameCoords(ms);
2051 }
2052
2053 /*!
2054  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2055  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2056  * cellIds is not given explicitly but by a range python like.
2057  *
2058  * \param start starting ID
2059  * \param end end ID (excluded)
2060  * \param step step size
2061  * \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.
2062  * \return a newly allocated
2063  *
2064  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2065  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2066  */
2067 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
2068 {
2069   if(getMeshDimension()!=-1)
2070     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2071   else
2072     {
2073       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2074       if(newNbOfCells!=1)
2075         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2076       if(start!=0)
2077         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2078       incrRef();
2079       return const_cast<MEDCouplingUMesh *>(this);
2080     }
2081 }
2082
2083 /*!
2084  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2085  * The result mesh shares or not the node coordinates array with \a this mesh depending
2086  * on \a keepCoords parameter.
2087  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2088  *           to write this mesh to the MED file, its cells must be sorted using
2089  *           sortCellsInMEDFileFrmt().
2090  *  \param [in] begin - an array of cell ids to include to the new mesh.
2091  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2092  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2093  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2094  *         by calling zipCoords().
2095  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2096  *         to delete this mesh using decrRef() as it is no more needed.
2097  *  \throw If the coordinates array is not set.
2098  *  \throw If the nodal connectivity of cells is not defined.
2099  *  \throw If any cell id in the array \a begin is not valid.
2100  *
2101  *  \if ENABLE_EXAMPLES
2102  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2103  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2104  *  \endif
2105  */
2106 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2107 {
2108   if(getMeshDimension()!=-1)
2109     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2110   else
2111     {
2112       if(end-begin!=1)
2113         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2114       if(begin[0]!=0)
2115         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2116       incrRef();
2117       return const_cast<MEDCouplingUMesh *>(this);
2118     }
2119 }
2120
2121 /*!
2122  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2123  *
2124  * 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.
2125  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2126  * The number of cells of \b this will remain the same with this method.
2127  *
2128  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2129  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2130  * \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 ).
2131  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2132  */
2133 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2134 {
2135   checkConnectivityFullyDefined();
2136   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2137   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2138     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2139   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2140     {
2141       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2142       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2143       throw INTERP_KERNEL::Exception(oss.str());
2144     }
2145   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2146   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2147     {
2148       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2149       throw INTERP_KERNEL::Exception(oss.str());
2150     }
2151   mcIdType nbOfCells(getNumberOfCells());
2152   bool easyAssign(true);
2153   const mcIdType *connI(_nodal_connec_index->begin());
2154   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2155   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2156     {
2157       if(*it>=0 && *it<nbOfCells)
2158         {
2159           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2160         }
2161       else
2162         {
2163           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2164           throw INTERP_KERNEL::Exception(oss.str());
2165         }
2166     }
2167   if(easyAssign)
2168     {
2169       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2170       computeTypes();
2171     }
2172   else
2173     {
2174       DataArrayIdType *arrOut=0,*arrIOut=0;
2175       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2176                                                arrOut,arrIOut);
2177       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2178       setConnectivity(arrOut,arrIOut,true);
2179     }
2180 }
2181
2182 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2183 {
2184   checkConnectivityFullyDefined();
2185   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2186   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2187     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2188   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2189     {
2190       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2191       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2192       throw INTERP_KERNEL::Exception(oss.str());
2193     }
2194   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2195   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2196     {
2197       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2198       throw INTERP_KERNEL::Exception(oss.str());
2199     }
2200   mcIdType nbOfCells=getNumberOfCells();
2201   bool easyAssign=true;
2202   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2203   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2204   mcIdType it=start;
2205   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2206     {
2207       if(it>=0 && it<nbOfCells)
2208         {
2209           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2210         }
2211       else
2212         {
2213           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2214           throw INTERP_KERNEL::Exception(oss.str());
2215         }
2216     }
2217   if(easyAssign)
2218     {
2219       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2220       computeTypes();
2221     }
2222   else
2223     {
2224       DataArrayIdType *arrOut=0,*arrIOut=0;
2225       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2226                                                 arrOut,arrIOut);
2227       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2228       setConnectivity(arrOut,arrIOut,true);
2229     }
2230 }
2231
2232
2233 /*!
2234  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2235  * this->getMeshDimension(), that bound some cells of \a this mesh.
2236  * The cells of lower dimension to include to the result mesh are selected basing on
2237  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2238  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2239  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2240  * created mesh shares the node coordinates array with \a this mesh.
2241  *  \param [in] begin - the array of node ids.
2242  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2243  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2244  *         array \a begin are added, else cells whose any node is in the
2245  *         array \a begin are added.
2246  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2247  *         to delete this mesh using decrRef() as it is no more needed.
2248  *  \throw If the coordinates array is not set.
2249  *  \throw If the nodal connectivity of cells is not defined.
2250  *  \throw If any node id in \a begin is not valid.
2251  *
2252  *  \if ENABLE_EXAMPLES
2253  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2254  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2255  *  \endif
2256  */
2257 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2258 {
2259   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2260   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2261   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2262   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2263   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2264 }
2265
2266 /*!
2267  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2268  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2269  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2270  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2271  *         by calling zipCoords().
2272  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2273  *         to delete this mesh using decrRef() as it is no more needed.
2274  *  \throw If the coordinates array is not set.
2275  *  \throw If the nodal connectivity of cells is not defined.
2276  *
2277  *  \if ENABLE_EXAMPLES
2278  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2279  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2280  *  \endif
2281  */
2282 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2283 {
2284   DataArrayIdType *desc=DataArrayIdType::New();
2285   DataArrayIdType *descIndx=DataArrayIdType::New();
2286   DataArrayIdType *revDesc=DataArrayIdType::New();
2287   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2288   //
2289   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2290   revDesc->decrRef();
2291   desc->decrRef();
2292   descIndx->decrRef();
2293   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2294   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2295   std::vector<mcIdType> boundaryCells;
2296   for(mcIdType i=0;i<nbOfCells;i++)
2297     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2298       boundaryCells.push_back(i);
2299   revDescIndx->decrRef();
2300   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2301   return ret;
2302 }
2303
2304 /*!
2305  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2306  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2307  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2308  */
2309 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2310 {
2311   checkFullyDefined();
2312   MCAuto<DataArrayIdType> ret2(DataArrayIdType::New());
2313
2314   if (getNumberOfCells() == 0)
2315     {
2316       ret2->alloc(0,1);
2317       return ret2.retn();
2318     }
2319
2320   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
2321   //
2322   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2323   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2324   //
2325   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2326   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2327   const mcIdType *revDescPtr=revDesc->getConstPointer();
2328   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2329   mcIdType nbOfCells=getNumberOfCells();
2330   std::vector<bool> ret1(nbOfCells,false);
2331   mcIdType sz=0;
2332   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2333     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2334       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2335   //
2336   ret2->alloc(sz,1);
2337   mcIdType *ret2Ptr=ret2->getPointer();
2338   sz=0;
2339   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2340     if(*it)
2341       *ret2Ptr++=sz;
2342   ret2->setName("BoundaryCells");
2343   return ret2.retn();
2344 }
2345
2346 /*!
2347  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2348  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2349  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2350  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2351  *
2352  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2353  * 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
2354  * equals a cell in \b otherDimM1OnSameCoords.
2355  *
2356  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2357  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2358  *
2359  * \param [in] otherDimM1OnSameCoords other mesh
2360  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2361  * \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
2362  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2363  */
2364 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2365 {
2366   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2367     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2368   checkConnectivityFullyDefined();
2369   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2370   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2371     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2372   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2373   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2374   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2375   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2376   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2377   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2378   DataArrayIdType *idsOtherInConsti=0;
2379   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2380   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2381   if(!b)
2382     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2383   std::set<mcIdType> s1;
2384   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2385     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2386   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2387   s1arr_renum1->sort();
2388   cellIdsRk0=s0arr.retn();
2389   //cellIdsRk1=s_renum1.retn();
2390   cellIdsRk1=s1arr_renum1.retn();
2391 }
2392
2393 /*!
2394  * 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
2395  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2396  *
2397  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2398  */
2399 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2400 {
2401   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2402   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2403   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2404   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2405   //
2406   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2407   revDesc=0; desc=0; descIndx=0;
2408   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2409   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2410   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2411 }
2412
2413 /*!
2414  * Finds nodes lying on the boundary of \a this mesh.
2415  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2416  *          nodes. The caller is to delete this array using decrRef() as it is no
2417  *          more needed.
2418  *  \throw If the coordinates array is not set.
2419  *  \throw If the nodal connectivity of cells is node defined.
2420  *
2421  *  \if ENABLE_EXAMPLES
2422  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2423  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2424  *  \endif
2425  */
2426 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2427 {
2428   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2429   return skin->computeFetchedNodeIds();
2430 }
2431
2432 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2433 {
2434   incrRef();
2435   return const_cast<MEDCouplingUMesh *>(this);
2436 }
2437
2438 /*!
2439  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2440  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2441  * This method searches for nodes needed to be duplicated. Those are the nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2442  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords, it will be duplicated.
2443  * 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.
2444  *
2445  * \param [in] crackingMesh a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2446  *             parameter is altered during the call.
2447  * \return node ids which need to be duplicated following the algorithm explained above.
2448  *
2449  */
2450 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& crackingMesh) const
2451 {
2452   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2453   // which mimicks the C++
2454   using DAInt = MCAuto<DataArrayIdType>;
2455   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2456
2457   checkFullyDefined();
2458   crackingMesh.checkFullyDefined();
2459   if(getCoords()!=crackingMesh.getCoords())
2460     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2461   if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2462     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2463
2464   // Clean the M1 group (cracking mesh): the M1 cells which are part of M0 boundary are irrelevant (we can't create a crack on the boundary of M0!)
2465   MCUMesh m0skin = computeSkin();
2466   DataArrayIdType *idsToKeepP;
2467   m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2468   DAInt idsToKeep(idsToKeepP);
2469   DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells());  // discard cells on the skin of M0
2470   MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2471
2472   if (!otherDimM1OnSameCoords->getNumberOfCells())
2473     return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2474
2475   // Checking star-shaped M1 group:
2476   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2477   MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2478   DAInt dsi = rdit0->deltaShiftIndex();
2479   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.
2480   if(idsTmp0->getNumberOfTuples())
2481     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2482   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2483
2484   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2485   // ie nodes belonging to the boundary "cells" (might be points) of M1
2486   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2487   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2488   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2489   // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2490   //    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)
2491   //    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
2492   //    although they are technically on the skin of the cube.
2493   DAInt fNodes = m0skin->computeFetchedNodeIds();
2494   DAInt notDup = 0;
2495   if (getMeshDimension() == 3)
2496     {
2497       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2498       MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2499       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2500       DataArrayIdType * corresp=0;
2501       meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2502       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2503       // In the cube example above, this is a U-shaped polyline.
2504       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2505       corresp->decrRef();
2506       if (validIds->getNumberOfTuples())
2507         {
2508           // 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:
2509           // (the U-shaped polyline described above)
2510           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2511           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2512           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2513           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2514
2515           // Specific logic to handle singular points :
2516           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2517           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2518           //   algorithm would be duplicating too much ...
2519           // This is a costly algorithm so only go into it if a simple (non sufficient) criteria is met: a node connected to more than 3 segs in meshM2:
2520           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2521           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2522           dnu1=0;dnu2=0;dnu3=0;
2523           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2524           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2525           if (singPoints->getNumberOfTuples())
2526             {
2527               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2528               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2529               // should not be duplicated
2530               //    1. Extract N D cells touching U-shape line:
2531               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2532               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2533               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2534               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2535               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2536               DataArrayIdType *idsOfM1BNt;
2537               mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2538               DAInt idsOfM1BN(idsOfM1BNt);
2539               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2540               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2541               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2542               for(const auto& v: *idsOfM1BN)
2543                 {
2544                   if (v >= nCellsDesc)    // Keep valid match only
2545                     continue;
2546                   mcIdType idx0 = revDescIBNP[v];
2547                   // Keep the two cells on either side of the face v of M1:
2548                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2549                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2550                 }
2551               //    3. Build complement
2552               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2553               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2554               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2555               DAInt inters = boundNodes->buildIntersection(nod3);
2556               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2557             }
2558           notDup = xtrem->buildSubstraction(fNodes1);
2559         }
2560       else  // if (validIds-> ...)
2561         notDup = xtrem->buildSubstraction(fNodes);
2562     }
2563   else  // if (3D ...)
2564     notDup = xtrem->buildSubstraction(fNodes);
2565
2566   DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2567   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2568   return dupl.retn();
2569 }
2570
2571
2572 /*!
2573  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2574  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2575  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2576  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2577  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2578  *
2579  * \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.
2580  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2581  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2582  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2583  * \param [out] cellIdsNotModified cell ids in \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2584  *
2585  */
2586 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2587                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2588 {
2589   using DAInt = MCAuto<DataArrayIdType>;
2590   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2591
2592   checkFullyDefined();
2593   otherDimM1OnSameCoords.checkFullyDefined();
2594   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2595     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2596   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2597     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2598
2599   // Degenerated case - no nodes to duplicate
2600   if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2601     {
2602       cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2603       cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2604       return;
2605     }
2606
2607   // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2608   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2609   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2610   mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2611   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2612   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2613   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2614   DataArrayIdType *idsOfM1t;
2615   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2616   DAInt idsOfM1Large(idsOfM1t);
2617   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2618
2619   // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2620   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2621   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2622   DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2623   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2624   DataArrayIdType *neight=0, *neighIt=0;
2625   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2626   DAInt neighL(neight), neighIL(neighIt);
2627
2628   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2629   hitCellsLarge->fillWithValue(0);  // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2630   mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2631
2632   // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2633   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2634   for(const auto& v: *idsOfM1Large)
2635     {
2636       if (v >= nL) continue;   // Keep valid match only - see doc of areCellsIncludedIn()
2637       mcIdType idx0 = revDescILP[v];
2638       // Retrieve the two cells on either side of the face v of M1:
2639       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2640       std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2641       // Handle the spread zones on the two sides of the crack:
2642       for (const auto c: {c1, c2})
2643         {
2644           if (hitCellsLargeP[c]) continue;
2645           // Identify connex zone around this cell - if we find a value already assigned there, use it.
2646           mcIdType dnu;
2647           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2648           std::set<mcIdType> sv;
2649           for (const mcIdType& s: *spreadZone)
2650             if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2651           if (sv.size() > 1)
2652             // Strange: we find in the same spread zone a +1 and -1 !
2653             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2654           // If a valid value was found, use it:
2655           mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2656           // Hopefully this does not conflict with an potential value on the other side:
2657           mcIdType other = toOther[c];
2658           if (hitCellsLargeP[other])
2659             {
2660               if(val && hitCellsLargeP[other] != -val)
2661                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2662               // We do not yet have a value, but other side has one. Use it!
2663               if(!val) val = -hitCellsLargeP[other];
2664             }
2665           // Cover first initialisation:
2666           if (!val) val = 1;
2667           // And finally, fill the current spread zone:
2668           for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2669         }
2670     }
2671
2672   DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2673   DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2674
2675   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2676     {
2677       DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2678       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2679     }
2680   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2681   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2682   //
2683   cellIdsNeededToBeRenum=cellsRet1.retn();
2684   cellIdsNotModified=cellsRet2.retn();
2685 }
2686
2687 /*!
2688  * This method operates a modification of the connectivity and coords in \b this.
2689  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2690  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2691  * 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
2692  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2693  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2694  *
2695  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2696  *
2697  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2698  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2699  */
2700 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2701 {
2702   mcIdType nbOfNodes=getNumberOfNodes();
2703   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2704   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2705 }
2706
2707 /*!
2708  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2709  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2710  *
2711  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2712  *
2713  * \sa renumberNodesInConn
2714  */
2715 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2716 {
2717   checkConnectivityFullyDefined();
2718   mcIdType *conn(getNodalConnectivity()->getPointer());
2719   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2720   mcIdType nbOfCells=getNumberOfCells();
2721   for(mcIdType i=0;i<nbOfCells;i++)
2722     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2723       {
2724         mcIdType& node=conn[iconn];
2725         if(node>=0)//avoid polyhedron separator
2726           {
2727             node+=offset;
2728           }
2729       }
2730   _nodal_connec->declareAsNew();
2731   updateTime();
2732 }
2733
2734 /*!
2735  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2736  *  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
2737  *  of a big mesh.
2738  */
2739 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2740 {
2741   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2742 }
2743
2744 /*!
2745  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2746  *  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
2747  *  of a big mesh.
2748  */
2749 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2750 {
2751   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2752 }
2753
2754 /*!
2755  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2756  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2757  * This method is a generalization of shiftNodeNumbersInConn().
2758  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2759  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2760  *         this->getNumberOfNodes(), in "Old to New" mode.
2761  *         See \ref numbering for more info on renumbering modes.
2762  *  \throw If the nodal connectivity of cells is not defined.
2763  *
2764  *  \if ENABLE_EXAMPLES
2765  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2766  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2767  *  \endif
2768  */
2769 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2770 {
2771   checkConnectivityFullyDefined();
2772   mcIdType *conn=getNodalConnectivity()->getPointer();
2773   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2774   mcIdType nbOfCells=getNumberOfCells();
2775   for(mcIdType i=0;i<nbOfCells;i++)
2776     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2777       {
2778         mcIdType& node=conn[iconn];
2779         if(node>=0)//avoid polyhedron separator
2780           {
2781             node=newNodeNumbersO2N[node];
2782           }
2783       }
2784   _nodal_connec->declareAsNew();
2785   updateTime();
2786 }
2787
2788 /*!
2789  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2790  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2791  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2792  *
2793  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2794  */
2795 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2796 {
2797   checkConnectivityFullyDefined();
2798   mcIdType *conn=getNodalConnectivity()->getPointer();
2799   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2800   mcIdType nbOfCells=getNumberOfCells();
2801   for(mcIdType i=0;i<nbOfCells;i++)
2802     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2803       {
2804         mcIdType& node=conn[iconn];
2805         if(node>=0)//avoid polyhedron separator
2806           {
2807             node+=delta;
2808           }
2809       }
2810   _nodal_connec->declareAsNew();
2811   updateTime();
2812 }
2813
2814 /*!
2815  * This method operates a modification of the connectivity in \b this.
2816  * 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.
2817  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2818  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2819  * 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
2820  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2821  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2822  *
2823  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2824  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2825  *
2826  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2827  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2828  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2829  */
2830 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2831 {
2832   checkConnectivityFullyDefined();
2833   std::map<mcIdType,mcIdType> m;
2834   mcIdType val=offset;
2835   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2836     m[*work]=val;
2837   mcIdType *conn=getNodalConnectivity()->getPointer();
2838   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2839   mcIdType nbOfCells=getNumberOfCells();
2840   for(mcIdType i=0;i<nbOfCells;i++)
2841     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2842       {
2843         mcIdType& node=conn[iconn];
2844         if(node>=0)//avoid polyhedron separator
2845           {
2846             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2847             if(it!=m.end())
2848               node=(*it).second;
2849           }
2850       }
2851   updateTime();
2852 }
2853
2854 /*!
2855  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2856  *
2857  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2858  * After the call of this method the number of cells remains the same as before.
2859  *
2860  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2861  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2862  * be strictly in [0;this->getNumberOfCells()).
2863  *
2864  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2865  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2866  * should be contained in[0;this->getNumberOfCells()).
2867  *
2868  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2869  * \param check whether to check content of old2NewBg
2870  */
2871 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2872 {
2873   checkConnectivityFullyDefined();
2874   mcIdType nbCells=getNumberOfCells();
2875   const mcIdType *array=old2NewBg;
2876   if(check)
2877     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2878   //
2879   const mcIdType *conn=_nodal_connec->getConstPointer();
2880   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2881   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2882   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2883   const mcIdType *n2oPtr=n2o->begin();
2884   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2885   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2886   newConn->copyStringInfoFrom(*_nodal_connec);
2887   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2888   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2889   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2890   //
2891   mcIdType *newC=newConn->getPointer();
2892   mcIdType *newCI=newConnI->getPointer();
2893   mcIdType loc=0;
2894   newCI[0]=loc;
2895   for(mcIdType i=0;i<nbCells;i++)
2896     {
2897       mcIdType pos=n2oPtr[i];
2898       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2899       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2900       loc+=nbOfElts;
2901       newCI[i+1]=loc;
2902     }
2903   //
2904   setConnectivity(newConn,newConnI);
2905   if(check)
2906     free(const_cast<mcIdType *>(array));
2907 }
2908
2909 /*!
2910  * Finds cells whose bounding boxes intersect a given bounding box.
2911  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2912  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2913  *         zMax (if in 3D).
2914  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2915  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2916  *         extent of the bounding box of cell to produce an addition to this bounding box.
2917  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2918  *         cells. The caller is to delete this array using decrRef() as it is no more
2919  *         needed.
2920  *  \throw If the coordinates array is not set.
2921  *  \throw If the nodal connectivity of cells is not defined.
2922  *
2923  *  \if ENABLE_EXAMPLES
2924  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2925  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2926  *  \endif
2927  */
2928 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2929 {
2930   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2931   if(getMeshDimension()==-1)
2932     {
2933       elems->pushBackSilent(0);
2934       return elems.retn();
2935     }
2936   int dim=getSpaceDimension();
2937   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2938   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2939   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2940   const double* coords = getCoords()->getConstPointer();
2941   mcIdType nbOfCells=getNumberOfCells();
2942   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2943     {
2944       for (int i=0; i<dim; i++)
2945         {
2946           elem_bb[i*2]=std::numeric_limits<double>::max();
2947           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2948         }
2949
2950       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2951         {
2952           mcIdType node= conn[inode];
2953           if(node>=0)//avoid polyhedron separator
2954             {
2955               for (int idim=0; idim<dim; idim++)
2956                 {
2957                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2958                     {
2959                       elem_bb[idim*2] = coords[node*dim+idim] ;
2960                     }
2961                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2962                     {
2963                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2964                     }
2965                 }
2966             }
2967         }
2968       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2969         elems->pushBackSilent(ielem);
2970     }
2971   return elems.retn();
2972 }
2973
2974 /*!
2975  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2976  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2977  * added in 'elems' parameter.
2978  */
2979 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2980 {
2981   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2982   if(getMeshDimension()==-1)
2983     {
2984       elems->pushBackSilent(0);
2985       return elems.retn();
2986     }
2987   int dim=getSpaceDimension();
2988   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2989   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2990   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2991   const double* coords = getCoords()->getConstPointer();
2992   mcIdType nbOfCells=getNumberOfCells();
2993   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2994     {
2995       for (int i=0; i<dim; i++)
2996         {
2997           elem_bb[i*2]=std::numeric_limits<double>::max();
2998           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2999         }
3000
3001       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3002         {
3003           mcIdType node= conn[inode];
3004           if(node>=0)//avoid polyhedron separator
3005             {
3006               for (int idim=0; idim<dim; idim++)
3007                 {
3008                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
3009                     {
3010                       elem_bb[idim*2] = coords[node*dim+idim] ;
3011                     }
3012                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3013                     {
3014                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
3015                     }
3016                 }
3017             }
3018         }
3019       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3020         elems->pushBackSilent(ielem);
3021     }
3022   return elems.retn();
3023 }
3024
3025 /*!
3026  * Returns a type of a cell by its id.
3027  *  \param [in] cellId - the id of the cell of interest.
3028  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3029  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3030  */
3031 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3032 {
3033   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3034   if(cellId<_nodal_connec_index->getNbOfElems()-1)
3035     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3036   else
3037     {
3038       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3039       throw INTERP_KERNEL::Exception(oss.str());
3040     }
3041 }
3042
3043 /*!
3044  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3045  * This method does not throw exception if geometric type \a type is not in \a this.
3046  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3047  * The coordinates array is not considered here.
3048  *
3049  * \param [in] type the geometric type
3050  * \return cell ids in this having geometric type \a type.
3051  */
3052 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3053 {
3054
3055   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3056   ret->alloc(0,1);
3057   checkConnectivityFullyDefined();
3058   mcIdType nbCells=getNumberOfCells();
3059   int mdim=getMeshDimension();
3060   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3061   if(mdim!=ToIdType(cm.getDimension()))
3062     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3063   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3064   const mcIdType *pt=_nodal_connec->getConstPointer();
3065   for(mcIdType i=0;i<nbCells;i++)
3066     {
3067       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3068         ret->pushBackSilent(i);
3069     }
3070   return ret.retn();
3071 }
3072
3073 /*!
3074  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3075  */
3076 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3077 {
3078   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3079   mcIdType nbOfCells(getNumberOfCells()),ret(0);
3080   for(mcIdType i=0;i<nbOfCells;i++)
3081     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3082       ret++;
3083   return ret;
3084 }
3085
3086 /*!
3087  * Returns the nodal connectivity of a given cell.
3088  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3089  * all returned node ids can be used in getCoordinatesOfNode().
3090  *  \param [in] cellId - an id of the cell of interest.
3091  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3092  *         cleared before the appending.
3093  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3094  */
3095 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3096 {
3097   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3098   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3099     if(*w>=0)
3100       conn.push_back(*w);
3101 }
3102
3103 std::string MEDCouplingUMesh::simpleRepr() const
3104 {
3105   static const char msg0[]="No coordinates specified !";
3106   std::ostringstream ret;
3107   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3108   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3109   int tmpp1,tmpp2;
3110   double tt=getTime(tmpp1,tmpp2);
3111   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3112   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3113   if(_mesh_dim>=-1)
3114     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3115   else
3116     { ret << " Mesh dimension has not been set or is invalid !"; }
3117   if(_coords!=0)
3118     {
3119       const int spaceDim=getSpaceDimension();
3120       ret << spaceDim << "\nInfo attached on space dimension : ";
3121       for(int i=0;i<spaceDim;i++)
3122         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3123       ret << "\n";
3124     }
3125   else
3126     ret << msg0 << "\n";
3127   ret << "Number of nodes : ";
3128   if(_coords!=0)
3129     ret << getNumberOfNodes() << "\n";
3130   else
3131     ret << msg0 << "\n";
3132   ret << "Number of cells : ";
3133   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3134     ret << getNumberOfCells() << "\n";
3135   else
3136     ret << "No connectivity specified !" << "\n";
3137   ret << "Cell types present : ";
3138   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3139     {
3140       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3141       ret << cm.getRepr() << " ";
3142     }
3143   ret << "\n";
3144   return ret.str();
3145 }
3146
3147 std::string MEDCouplingUMesh::advancedRepr() const
3148 {
3149   std::ostringstream ret;
3150   ret << simpleRepr();
3151   ret << "\nCoordinates array : \n___________________\n\n";
3152   if(_coords)
3153     _coords->reprWithoutNameStream(ret);
3154   else
3155     ret << "No array set !\n";
3156   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3157   reprConnectivityOfThisLL(ret);
3158   return ret.str();
3159 }
3160
3161 /*!
3162  * This method returns a C++ code that is a dump of \a this.
3163  * This method will throw if this is not fully defined.
3164  */
3165 std::string MEDCouplingUMesh::cppRepr() const
3166 {
3167   static const char coordsName[]="coords";
3168   static const char connName[]="conn";
3169   static const char connIName[]="connI";
3170   checkFullyDefined();
3171   std::ostringstream ret; ret << "// coordinates" << std::endl;
3172   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3173   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3174   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3175   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3176   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3177   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3178   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3179   return ret.str();
3180 }
3181
3182 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3183 {
3184   std::ostringstream ret;
3185   reprConnectivityOfThisLL(ret);
3186   return ret.str();
3187 }
3188
3189 /*!
3190  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3191  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3192  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3193  * some algos).
3194  *
3195  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3196  * 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
3197  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3198  */
3199 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3200 {
3201   int mdim=getMeshDimension();
3202   if(mdim<0)
3203     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3204   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3205   MCAuto<DataArrayIdType> tmp1,tmp2;
3206   bool needToCpyCT=true;
3207   if(!_nodal_connec)
3208     {
3209       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3210       needToCpyCT=false;
3211     }
3212   else
3213     {
3214       tmp1=_nodal_connec;
3215       tmp1->incrRef();
3216     }
3217   if(!_nodal_connec_index)
3218     {
3219       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3220       needToCpyCT=false;
3221     }
3222   else
3223     {
3224       tmp2=_nodal_connec_index;
3225       tmp2->incrRef();
3226     }
3227   ret->setConnectivity(tmp1,tmp2,false);
3228   if(needToCpyCT)
3229     ret->_types=_types;
3230   if(!_coords)
3231     {
3232       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3233       ret->setCoords(coords);
3234     }
3235   else
3236     ret->setCoords(_coords);
3237   return ret.retn();
3238 }
3239
3240 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3241 {
3242   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3243   const mcIdType *pt=_nodal_connec->getConstPointer();
3244   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3245     return ptI[cellId+1]-ptI[cellId]-1;
3246   else
3247     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3248 }
3249
3250 /*!
3251  * Returns types of cells of the specified part of \a this mesh.
3252  * This method avoids computing sub-mesh explicitly to get its types.
3253  *  \param [in] begin - an array of cell ids of interest.
3254  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3255  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3256  *         describing the cell types.
3257  *  \throw If the coordinates array is not set.
3258  *  \throw If the nodal connectivity of cells is not defined.
3259  *  \sa getAllGeoTypes()
3260  */
3261 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3262 {
3263   checkFullyDefined();
3264   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3265   const mcIdType *conn=_nodal_connec->getConstPointer();
3266   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3267   for(const mcIdType *w=begin;w!=end;w++)
3268     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3269   return ret;
3270 }
3271
3272 /*!
3273  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3274  * Optionally updates
3275  * a set of types of cells constituting \a this mesh.
3276  * This method is for advanced users having prepared their connectivity before. For
3277  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3278  *  \param [in] conn - the nodal connectivity array.
3279  *  \param [in] connIndex - the nodal connectivity index array.
3280  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3281  *         mesh is updated.
3282  */
3283 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3284 {
3285   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3286   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3287   if(isComputingTypes)
3288     computeTypes();
3289   declareAsNew();
3290 }
3291
3292 /*!
3293  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3294  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3295  */
3296 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3297     _nodal_connec(0),_nodal_connec_index(0),
3298     _types(other._types)
3299 {
3300   if(other._nodal_connec)
3301     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3302   if(other._nodal_connec_index)
3303     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3304 }
3305
3306 MEDCouplingUMesh::~MEDCouplingUMesh()
3307 {
3308   if(_nodal_connec)
3309     _nodal_connec->decrRef();
3310   if(_nodal_connec_index)
3311     _nodal_connec_index->decrRef();
3312 }
3313
3314 /*!
3315  * Recomputes a set of cell types of \a this mesh. For more info see
3316  * \ref MEDCouplingUMeshNodalConnectivity.
3317  */
3318 void MEDCouplingUMesh::computeTypes()
3319 {
3320   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3321 }
3322
3323
3324 /*!
3325  * Returns a number of cells constituting \a this mesh.
3326  *  \return mcIdType - the number of cells in \a this mesh.
3327  *  \throw If the nodal connectivity of cells is not defined.
3328  */
3329 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3330 {
3331   if(_nodal_connec_index)
3332     return _nodal_connec_index->getNumberOfTuples()-1;
3333   else
3334     if(_mesh_dim==-1)
3335       return 1;
3336     else
3337       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3338 }
3339
3340 /*!
3341  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3342  * mesh. For more info see \ref meshes.
3343  *  \return int - the dimension of \a this mesh.
3344  *  \throw If the mesh dimension is not defined using setMeshDimension().
3345  */
3346 int MEDCouplingUMesh::getMeshDimension() const
3347 {
3348   if(_mesh_dim<-1)
3349     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3350   return _mesh_dim;
3351 }
3352
3353 /*!
3354  * Returns a length of the nodal connectivity array.
3355  * This method is for test reason. Normally the integer returned is not useable by
3356  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3357  *  \return mcIdType - the length of the nodal connectivity array.
3358  */
3359 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3360 {
3361   return _nodal_connec->getNbOfElems();
3362 }
3363
3364 /*!
3365  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3366  */
3367 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3368 {
3369   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3370   tinyInfo.push_back(ToIdType(getMeshDimension()));
3371   tinyInfo.push_back(getNumberOfCells());
3372   if(_nodal_connec)
3373     tinyInfo.push_back(getNodalConnectivityArrayLen());
3374   else
3375     tinyInfo.push_back(-1);
3376 }
3377
3378 /*!
3379  * First step of unserialization process.
3380  */
3381 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3382 {
3383   return tinyInfo[6]<=0;
3384 }
3385
3386 /*!
3387  * Second step of serialization process.
3388  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3389  * \param a1 DataArrayDouble
3390  * \param a2 DataArrayDouble
3391  * \param littleStrings string vector
3392  */
3393 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3394 {
3395   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3396   if(tinyInfo[5]!=-1)
3397     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3398 }
3399
3400 /*!
3401  * Third and final step of serialization process.
3402  */
3403 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3404 {
3405   MEDCouplingPointSet::serialize(a1,a2);
3406   if(getMeshDimension()>-1)
3407     {
3408       a1=DataArrayIdType::New();
3409       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3410       mcIdType *ptA1=a1->getPointer();
3411       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3412       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3413       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3414       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3415     }
3416   else
3417     a1=0;
3418 }
3419
3420 /*!
3421  * Second and final unserialization process.
3422  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3423  */
3424 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3425 {
3426   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3427   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3428   if(tinyInfo[7]!=-1)
3429     {
3430       // Connectivity
3431       const mcIdType *recvBuffer=a1->getConstPointer();
3432       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3433       myConnecIndex->alloc(tinyInfo[6]+1,1);
3434       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3435       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3436       myConnec->alloc(tinyInfo[7],1);
3437       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3438       setConnectivity(myConnec, myConnecIndex);
3439     }
3440 }
3441
3442
3443
3444 /*!
3445  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3446  * mesh.<br>
3447  * For 1D cells, the returned field contains lengths.<br>
3448  * For 2D cells, the returned field contains areas.<br>
3449  * For 3D cells, the returned field contains volumes.
3450  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3451  *         orientation, i.e. the volume is always positive.
3452  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3453  *         and one time . The caller is to delete this field using decrRef() as it is no
3454  *         more needed.
3455  */
3456 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3457 {
3458   std::string name="MeasureOfMesh_";
3459   name+=getName();
3460   mcIdType nbelem=getNumberOfCells();
3461   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3462   field->setName(name);
3463   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3464   array->alloc(nbelem,1);
3465   double *area_vol=array->getPointer();
3466   field->setArray(array) ; array=0;
3467   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3468   field->synchronizeTimeWithMesh();
3469   if(getMeshDimension()!=-1)
3470     {
3471       mcIdType ipt;
3472       INTERP_KERNEL::NormalizedCellType type;
3473       int dim_space=getSpaceDimension();
3474       const double *coords=getCoords()->getConstPointer();
3475       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3476       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3477       for(mcIdType iel=0;iel<nbelem;iel++)
3478         {
3479           ipt=connec_index[iel];
3480           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3481           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);
3482         }
3483       if(isAbs)
3484         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3485     }
3486   else
3487     {
3488       area_vol[0]=std::numeric_limits<double>::max();
3489     }
3490   return field.retn();
3491 }
3492
3493 /*!
3494  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3495  * mesh.<br>
3496  * For 1D cells, the returned array contains lengths.<br>
3497  * For 2D cells, the returned array contains areas.<br>
3498  * For 3D cells, the returned array contains volumes.
3499  * This method avoids building explicitly a part of \a this mesh to perform the work.
3500  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3501  *         orientation, i.e. the volume is always positive.
3502  *  \param [in] begin - an array of cell ids of interest.
3503  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3504  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3505  *          delete this array using decrRef() as it is no more needed.
3506  *
3507  *  \if ENABLE_EXAMPLES
3508  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3509  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3510  *  \endif
3511  *  \sa getMeasureField()
3512  */
3513 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3514 {
3515   std::string name="PartMeasureOfMesh_";
3516   name+=getName();
3517   std::size_t nbelem=std::distance(begin,end);
3518   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3519   array->setName(name);
3520   array->alloc(nbelem,1);
3521   double *area_vol=array->getPointer();
3522   if(getMeshDimension()!=-1)
3523     {
3524       mcIdType ipt;
3525       INTERP_KERNEL::NormalizedCellType type;
3526       int dim_space=getSpaceDimension();
3527       const double *coords=getCoords()->getConstPointer();
3528       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3529       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3530       for(const mcIdType *iel=begin;iel!=end;iel++)
3531         {
3532           ipt=connec_index[*iel];
3533           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3534           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3535         }
3536       if(isAbs)
3537         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3538     }
3539   else
3540     {
3541       area_vol[0]=std::numeric_limits<double>::max();
3542     }
3543   return array.retn();
3544 }
3545
3546 /*!
3547  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3548  * \a this one. The returned field contains the dual cell volume for each corresponding
3549  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3550  *  the dual mesh in P1 sens of \a this.<br>
3551  * For 1D cells, the returned field contains lengths.<br>
3552  * For 2D cells, the returned field contains areas.<br>
3553  * For 3D cells, the returned field contains volumes.
3554  * This method is useful to check "P1*" conservative interpolators.
3555  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3556  *         orientation, i.e. the volume is always positive.
3557  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3558  *          nodes and one time. The caller is to delete this array using decrRef() as
3559  *          it is no more needed.
3560  */
3561 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3562 {
3563   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3564   std::string name="MeasureOnNodeOfMesh_";
3565   name+=getName();
3566   mcIdType nbNodes=getNumberOfNodes();
3567   MCAuto<DataArrayDouble> nnpc;
3568   {
3569     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3570     nnpc=tmp2->convertToDblArr();
3571   }
3572   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3573   const double *nnpcPtr(nnpc->begin());
3574   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3575   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3576   array->alloc(nbNodes,1);
3577   double *valsToFill=array->getPointer();
3578   std::fill(valsToFill,valsToFill+nbNodes,0.);
3579   const double *values=tmp->getArray()->getConstPointer();
3580   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3581   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3582   getReverseNodalConnectivity(da,daInd);
3583   const mcIdType *daPtr=da->getConstPointer();
3584   const mcIdType *daIPtr=daInd->getConstPointer();
3585   for(mcIdType i=0;i<nbNodes;i++)
3586     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3587       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3588   ret->setMesh(this);
3589   ret->setArray(array);
3590   return ret.retn();
3591 }
3592
3593 /*!
3594  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3595  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3596  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3597  * and are normalized.
3598  * <br> \a this can be either
3599  * - a  2D mesh in 2D or 3D space or
3600  * - an 1D mesh in 2D space.
3601  *
3602  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3603  *          cells and one time. The caller is to delete this field using decrRef() as
3604  *          it is no more needed.
3605  *  \throw If the nodal connectivity of cells is not defined.
3606  *  \throw If the coordinates array is not set.
3607  *  \throw If the mesh dimension is not set.
3608  *  \throw If the mesh and space dimension is not as specified above.
3609  */
3610 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3611 {
3612   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3613     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3614   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3615   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3616   mcIdType nbOfCells=getNumberOfCells();
3617   int nbComp=getMeshDimension()+1;
3618   array->alloc(nbOfCells,nbComp);
3619   double *vals=array->getPointer();
3620   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3621   const mcIdType *conn=_nodal_connec->getConstPointer();
3622   const double *coords=_coords->getConstPointer();
3623   if(getMeshDimension()==2)
3624     {
3625       if(getSpaceDimension()==3)
3626         {
3627           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3628           const double *locPtr=loc->getConstPointer();
3629           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3630             {
3631               mcIdType offset=connI[i];
3632               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3633               double n=INTERP_KERNEL::norm<3>(vals);
3634               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3635             }
3636         }
3637       else
3638         {
3639           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3640           const double *isAbsPtr=isAbs->getArray()->begin();
3641           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3642             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3643         }
3644     }
3645   else//meshdimension==1
3646     {
3647       double tmp[2];
3648       for(mcIdType i=0;i<nbOfCells;i++)
3649         {
3650           mcIdType offset=connI[i];
3651           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3652           double n=INTERP_KERNEL::norm<2>(tmp);
3653           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3654           *vals++=-tmp[1];
3655           *vals++=tmp[0];
3656         }
3657     }
3658   ret->setArray(array);
3659   ret->setMesh(this);
3660   ret->synchronizeTimeWithSupport();
3661   return ret.retn();
3662 }
3663
3664 /*!
3665  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3666  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3667  * and are normalized.
3668  * <br> \a this can be either
3669  * - a  2D mesh in 2D or 3D space or
3670  * - an 1D mesh in 2D space.
3671  *
3672  * This method avoids building explicitly a part of \a this mesh to perform the work.
3673  *  \param [in] begin - an array of cell ids of interest.
3674  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3675  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3676  *          cells and one time. The caller is to delete this field using decrRef() as
3677  *          it is no more needed.
3678  *  \throw If the nodal connectivity of cells is not defined.
3679  *  \throw If the coordinates array is not set.
3680  *  \throw If the mesh dimension is not set.
3681  *  \throw If the mesh and space dimension is not as specified above.
3682  *  \sa buildOrthogonalField()
3683  *
3684  *  \if ENABLE_EXAMPLES
3685  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3686  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3687  *  \endif
3688  */
3689 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3690 {
3691   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3692     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3693   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3694   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3695   std::size_t nbelems=std::distance(begin,end);
3696   int nbComp=getMeshDimension()+1;
3697   array->alloc(nbelems,nbComp);
3698   double *vals=array->getPointer();
3699   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3700   const mcIdType *conn=_nodal_connec->getConstPointer();
3701   const double *coords=_coords->getConstPointer();
3702   if(getMeshDimension()==2)
3703     {
3704       if(getSpaceDimension()==3)
3705         {
3706           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3707           const double *locPtr=loc->getConstPointer();
3708           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3709             {
3710               mcIdType offset=connI[*i];
3711               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3712               double n=INTERP_KERNEL::norm<3>(vals);
3713               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3714             }
3715         }
3716       else
3717         {
3718           for(std::size_t i=0;i<nbelems;i++)
3719             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3720         }
3721     }
3722   else//meshdimension==1
3723     {
3724       double tmp[2];
3725       for(const mcIdType *i=begin;i!=end;i++)
3726         {
3727           mcIdType offset=connI[*i];
3728           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3729           double n=INTERP_KERNEL::norm<2>(tmp);
3730           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3731           *vals++=-tmp[1];
3732           *vals++=tmp[0];
3733         }
3734     }
3735   ret->setArray(array);
3736   ret->setMesh(this);
3737   ret->synchronizeTimeWithSupport();
3738   return ret.retn();
3739 }
3740
3741 /*!
3742  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3743  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3744  * and are \b not normalized.
3745  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3746  *          cells and one time. The caller is to delete this field using decrRef() as
3747  *          it is no more needed.
3748  *  \throw If the nodal connectivity of cells is not defined.
3749  *  \throw If the coordinates array is not set.
3750  *  \throw If \a this->getMeshDimension() != 1.
3751  *  \throw If \a this mesh includes cells of type other than SEG2.
3752  */
3753 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3754 {
3755   if(getMeshDimension()!=1)
3756     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3757   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3758     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3759   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3760   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3761   mcIdType nbOfCells=getNumberOfCells();
3762   int spaceDim=getSpaceDimension();
3763   array->alloc(nbOfCells,spaceDim);
3764   double *pt=array->getPointer();
3765   const double *coo=getCoords()->getConstPointer();
3766   std::vector<mcIdType> conn;
3767   conn.reserve(2);
3768   for(mcIdType i=0;i<nbOfCells;i++)
3769     {
3770       conn.resize(0);
3771       getNodeIdsOfCell(i,conn);
3772       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3773     }
3774   ret->setArray(array);
3775   ret->setMesh(this);
3776   ret->synchronizeTimeWithSupport();
3777   return ret.retn();
3778 }
3779
3780 /*!
3781  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3782  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3783  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3784  * from. If a result face is shared by two 3D cells, then the face in included twice in
3785  * the result mesh.
3786  *  \param [in] origin - 3 components of a point defining location of the plane.
3787  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3788  *         must be greater than 1e-6.
3789  *  \param [in] eps - half-thickness of the plane.
3790  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3791  *         producing correspondent 2D cells. The caller is to delete this array
3792  *         using decrRef() as it is no more needed.
3793  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3794  *         not share the node coordinates array with \a this mesh. The caller is to
3795  *         delete this mesh using decrRef() as it is no more needed.
3796  *  \throw If the coordinates array is not set.
3797  *  \throw If the nodal connectivity of cells is not defined.
3798  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3799  *  \throw If magnitude of \a vec is less than 1e-6.
3800  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3801  *  \throw If \a this includes quadratic cells.
3802  */
3803 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3804 {
3805   checkFullyDefined();
3806   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3807     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3808   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3809   if(candidates->empty())
3810     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3811   std::vector<mcIdType> nodes;
3812   DataArrayIdType *cellIds1D=0;
3813   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3814   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3815   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3816   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3817   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3818   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3819   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3820   revDesc2=0; revDescIndx2=0;
3821   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3822   revDesc1=0; revDescIndx1=0;
3823   //Marking all 1D cells that contained at least one node located on the plane
3824   //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3825   //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3826   //due to accuracy errors when the needed nodes already exist)
3827   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3828   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3829   //
3830   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3831   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3832     cut3DCurve[*it]=-1;
3833   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3834   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3835   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3836                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3837                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3838   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3839   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3840   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3841   if(cellIds2->empty())
3842     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3843   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3844   ret->setCoords(mDesc1->getCoords());
3845   ret->setConnectivity(conn,connI,true);
3846   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3847   return ret.retn();
3848 }
3849
3850 /*!
3851  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3852 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
3853 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3854 the result mesh.
3855  *  \param [in] origin - 3 components of a point defining location of the plane.
3856  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3857  *         must be greater than 1e-6.
3858  *  \param [in] eps - half-thickness of the plane.
3859  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3860  *         producing correspondent segments. The caller is to delete this array
3861  *         using decrRef() as it is no more needed.
3862  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3863  *         mesh in 3D space. This mesh does not share the node coordinates array with
3864  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3865  *         no more needed.
3866  *  \throw If the coordinates array is not set.
3867  *  \throw If the nodal connectivity of cells is not defined.
3868  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3869  *  \throw If magnitude of \a vec is less than 1e-6.
3870  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3871  *  \throw If \a this includes quadratic cells.
3872  */
3873 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3874 {
3875   checkFullyDefined();
3876   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3877     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3878   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3879   if(candidates->empty())
3880     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3881   std::vector<mcIdType> nodes;
3882   DataArrayIdType *cellIds1D(0);
3883   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3884   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3885   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3886   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3887   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3888   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3889   //
3890   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3891   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3892     cut3DCurve[*it]=-1;
3893   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3894   mcIdType ncellsSub=subMesh->getNumberOfCells();
3895   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3896   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3897                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3898                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3899   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3900   conn->alloc(0,1);
3901   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3902   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3903   for(mcIdType i=0;i<ncellsSub;i++)
3904     {
3905       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3906         {
3907           if(cut3DSurf[i].first!=-2)
3908             {
3909               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3910               connI->pushBackSilent(conn->getNumberOfTuples());
3911               cellIds2->pushBackSilent(i);
3912             }
3913           else
3914             {
3915               mcIdType cellId3DSurf=cut3DSurf[i].second;
3916               mcIdType offset=nodalI[cellId3DSurf]+1;
3917               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3918               for(mcIdType j=0;j<nbOfEdges;j++)
3919                 {
3920                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3921                   connI->pushBackSilent(conn->getNumberOfTuples());
3922                   cellIds2->pushBackSilent(cellId3DSurf);
3923                 }
3924             }
3925         }
3926     }
3927   if(cellIds2->empty())
3928     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3929   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3930   ret->setCoords(mDesc1->getCoords());
3931   ret->setConnectivity(conn,connI,true);
3932   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3933   return ret.retn();
3934 }
3935
3936 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3937 {
3938   checkFullyDefined();
3939   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3940     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3941   if(getNumberOfCells()!=1)
3942     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3943   //
3944   std::vector<mcIdType> nodes;
3945   findNodesOnPlane(origin,vec,eps,nodes);
3946   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());
3947   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3948   revDesc2=0; revDescIndx2=0;
3949   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3950   revDesc1=0; revDescIndx1=0;
3951   DataArrayIdType *cellIds1D(0);
3952   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3953   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3954   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3955   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3956     cut3DCurve[*it]=-1;
3957   bool sameNbNodes;
3958   {
3959     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3960     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3961     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3962   }
3963   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3964   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3965                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3966                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3967   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3968   connI->pushBackSilent(0); conn->alloc(0,1);
3969   {
3970     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3971     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3972     if(cellIds2->empty())
3973       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3974   }
3975   std::vector<std::vector<mcIdType> > res;
3976   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3977   std::size_t sz(res.size());
3978   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3979     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3980   for(std::size_t i=0;i<sz;i++)
3981     {
3982       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3983       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3984       connI->pushBackSilent(conn->getNumberOfTuples());
3985     }
3986   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3987   ret->setCoords(mDesc1->getCoords());
3988   ret->setConnectivity(conn,connI,true);
3989   mcIdType nbCellsRet(ret->getNumberOfCells());
3990   //
3991   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3992   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3993   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3994   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3995   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3996   MCAuto<DataArrayDouble> occm;
3997   {
3998     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3999     occm=DataArrayDouble::Substract(ccm,pt);
4000   }
4001   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4002   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);
4003   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4004   //
4005   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4006   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4007   ret2->setCoords(mDesc1->getCoords());
4008   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4009   conn2I->pushBackSilent(0); conn2->alloc(0,1);
4010   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4011   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4012   if(dott->getIJ(0,0)>0)
4013     {
4014       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4015       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4016     }
4017   else
4018     {
4019       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4020       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4021     }
4022   for(mcIdType i=1;i<nbCellsRet;i++)
4023     {
4024       if(dott2->getIJ(i,0)<0)
4025         {
4026           if(ciPtr[i+1]-ciPtr[i]>=4)
4027             {
4028               cell0.push_back(-1);
4029               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4030             }
4031         }
4032       else
4033         {
4034           if(ciPtr[i+1]-ciPtr[i]>=4)
4035             {
4036               cell1.push_back(-1);
4037               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4038             }
4039         }
4040     }
4041   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4042   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4043   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4044   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4045   ret2->setConnectivity(conn2,conn2I,true);
4046   ret2->checkConsistencyLight();
4047   ret2->orientCorrectlyPolyhedrons();
4048   return ret2;
4049 }
4050
4051 /*!
4052  * Finds cells whose bounding boxes intersect a given plane.
4053  *  \param [in] origin - 3 components of a point defining location of the plane.
4054  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4055  *         must be greater than 1e-6.
4056  *  \param [in] eps - half-thickness of the plane.
4057  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4058  *         cells. The caller is to delete this array using decrRef() as it is no more
4059  *         needed.
4060  *  \throw If the coordinates array is not set.
4061  *  \throw If the nodal connectivity of cells is not defined.
4062  *  \throw If \a this->getSpaceDimension() != 3.
4063  *  \throw If magnitude of \a vec is less than 1e-6.
4064  *  \sa buildSlice3D()
4065  */
4066 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4067 {
4068   checkFullyDefined();
4069   if(getSpaceDimension()!=3)
4070     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4071   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4072   if(normm<1e-6)
4073     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4074   double vec2[3];
4075   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4076   double angle=acos(vec[2]/normm);
4077   MCAuto<DataArrayIdType> cellIds;
4078   double bbox[6];
4079   if(angle>eps)
4080     {
4081       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4082       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4083       if(normm2/normm>1e-6)
4084         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4085       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4086       mw->setCoords(coo);
4087       mw->getBoundingBox(bbox);
4088       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4089       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4090     }
4091   else
4092     {
4093       getBoundingBox(bbox);
4094       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4095       cellIds=getCellsInBoundingBox(bbox,eps);
4096     }
4097   return cellIds.retn();
4098 }
4099
4100 /*!
4101  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4102  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4103  * No consideration of coordinate is done by this method.
4104  * 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)
4105  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4106  */
4107 bool MEDCouplingUMesh::isContiguous1D() const
4108 {
4109   if(getMeshDimension()!=1)
4110     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4111   mcIdType nbCells=getNumberOfCells();
4112   if(nbCells<1)
4113     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4114   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4115   mcIdType ref=conn[connI[0]+2];
4116   for(mcIdType i=1;i<nbCells;i++)
4117     {
4118       if(conn[connI[i]+1]!=ref)
4119         return false;
4120       ref=conn[connI[i]+2];
4121     }
4122   return true;
4123 }
4124
4125 /*!
4126  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4127  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4128  * \param pt reference point of the line
4129  * \param v normalized director vector of the line
4130  * \param eps max precision before throwing an exception
4131  * \param res output of size this->getNumberOfCells
4132  */
4133 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4134 {
4135   if(getMeshDimension()!=1)
4136     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4137   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4138     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4139   if(getSpaceDimension()!=3)
4140     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4141   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4142   const double *fPtr=f->getArray()->getConstPointer();
4143   double tmp[3];
4144   for(mcIdType i=0;i<getNumberOfCells();i++)
4145     {
4146       const double *tmp1=fPtr+3*i;
4147       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4148       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4149       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4150       double n1=INTERP_KERNEL::norm<3>(tmp);
4151       n1/=INTERP_KERNEL::norm<3>(tmp1);
4152       if(n1>eps)
4153         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4154     }
4155   const double *coo=getCoords()->getConstPointer();
4156   for(mcIdType i=0;i<getNumberOfNodes();i++)
4157     {
4158       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4159       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4160       res[i]=std::accumulate(tmp,tmp+3,0.);
4161     }
4162 }
4163
4164 /*!
4165  * 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.
4166  * \a this is expected to be a mesh so that its space dimension is equal to its
4167  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4168  * 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).
4169  *
4170  * 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
4171  * 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).
4172  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4173  *
4174  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4175  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4176  *
4177  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4178  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4179  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4180  * \return the positive value of the distance.
4181  * \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
4182  * dimension - 1.
4183  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4184  */
4185 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4186 {
4187   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4188   if(meshDim!=spaceDim-1)
4189     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4190   if(meshDim!=2 && meshDim!=1)
4191     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4192   checkFullyDefined();
4193   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4194     { 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()); }
4195   DataArrayIdType *ret1=0;
4196   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4197   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4198   MCAuto<DataArrayIdType> ret1Safe(ret1);
4199   cellId=*ret1Safe->begin();
4200   return *ret0->begin();
4201 }
4202
4203 /*!
4204  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4205  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4206  * 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
4207  * 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).
4208  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4209  *
4210  * \a this is expected to be a mesh so that its space dimension is equal to its
4211  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4212  * 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).
4213  *
4214  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4215  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4216  *
4217  * \param [in] pts the list of points in which each tuple represents a point
4218  * \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.
4219  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4220  * \throw if number of components of \a pts is not equal to the space dimension.
4221  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4222  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4223  */
4224 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4225 {
4226   if(!pts)
4227     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4228   pts->checkAllocated();
4229   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4230   if(meshDim!=spaceDim-1)
4231     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4232   if(meshDim!=2 && meshDim!=1)
4233     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4234   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4235     {
4236       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4237       throw INTERP_KERNEL::Exception(oss.str());
4238     }
4239   checkFullyDefined();
4240   mcIdType nbCells=getNumberOfCells();
4241   if(nbCells==0)
4242     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4243   mcIdType nbOfPts=pts->getNumberOfTuples();
4244   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4245   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4246   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4247   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4248   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4249   const double *bbox(bboxArr->begin());
4250   switch(spaceDim)
4251   {
4252     case 3:
4253       {
4254         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4255         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4256           {
4257             double x=std::numeric_limits<double>::max();
4258             std::vector<mcIdType> elems;
4259             myTree.getMinDistanceOfMax(ptsPtr,x);
4260             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4261             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4262           }
4263         break;
4264       }
4265     case 2:
4266       {
4267         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4268         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4269           {
4270             double x=std::numeric_limits<double>::max();
4271             std::vector<mcIdType> elems;
4272             myTree.getMinDistanceOfMax(ptsPtr,x);
4273             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4274             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4275           }
4276         break;
4277       }
4278     default:
4279       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4280   }
4281   cellIds=ret1.retn();
4282   return ret0.retn();
4283 }
4284
4285 /// @cond INTERNAL
4286
4287 /// @endcond
4288
4289 /*!
4290  * Finds cells in contact with a ball (i.e. a point with precision).
4291  * 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.
4292  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4293  *
4294  * \warning This method is suitable if the caller intends to evaluate only one
4295  *          point, for more points getCellsContainingPoints() is recommended as it is
4296  *          faster.
4297  *  \param [in] pos - array of coordinates of the ball central point.
4298  *  \param [in] eps - ball radius.
4299  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4300  *         if there are no such cells.
4301  *  \throw If the coordinates array is not set.
4302  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4303  */
4304 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4305 {
4306   std::vector<mcIdType> elts;
4307   getCellsContainingPoint(pos,eps,elts);
4308   if(elts.empty())
4309     return -1;
4310   return elts.front();
4311 }
4312
4313 /*!
4314  * Finds cells in contact with a ball (i.e. a point with precision).
4315  * 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.
4316  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4317  * \warning This method is suitable if the caller intends to evaluate only one
4318  *          point, for more points getCellsContainingPoints() is recommended as it is
4319  *          faster.
4320  *  \param [in] pos - array of coordinates of the ball central point.
4321  *  \param [in] eps - ball radius.
4322  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4323  *         before inserting ids.
4324  *  \throw If the coordinates array is not set.
4325  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4326  *
4327  *  \if ENABLE_EXAMPLES
4328  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4329  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4330  *  \endif
4331  */
4332 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4333 {
4334   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4335   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4336   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4337 }
4338
4339 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4340                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4341                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4342 {
4343   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4344   if(spaceDim==3)
4345     {
4346       if(mDim==3)
4347         {
4348           const double *coords=_coords->getConstPointer();
4349           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4350         }
4351       else
4352         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4353     }
4354   else if(spaceDim==2)
4355     {
4356       if(mDim==2)
4357         {
4358           const double *coords=_coords->getConstPointer();
4359           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4360         }
4361       else
4362         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4363     }
4364   else if(spaceDim==1)
4365     {
4366       if(mDim==1)
4367         {
4368           const double *coords=_coords->getConstPointer();
4369           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4370         }
4371       else
4372         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4373     }
4374   else
4375     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4376 }
4377
4378 /*!
4379  * Finds cells in contact with several balls (i.e. points with precision).
4380  * This method is an extension of getCellContainingPoint() and
4381  * getCellsContainingPoint() for the case of multiple points.
4382  * 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.
4383  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4384  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4385  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4386  *         this->getSpaceDimension() * \a nbOfPoints
4387  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4388  *  \param [in] eps - radius of balls (i.e. the precision).
4389  *  \param [out] elts - vector returning ids of found cells.
4390  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4391  *         dividing cell ids in \a elts into groups each referring to one
4392  *         point. Its every element (except the last one) is an index pointing to the
4393  *         first id of a group of cells. For example cells in contact with the *i*-th
4394  *         point are described by following range of indices:
4395  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4396  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4397  *         Number of cells in contact with the *i*-th point is
4398  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4399  *  \throw If the coordinates array is not set.
4400  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4401  *
4402  *  \if ENABLE_EXAMPLES
4403  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4404  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4405  *  \endif
4406  */
4407 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4408                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4409 {
4410   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4411   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4412 }
4413
4414 /*!
4415  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4416  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4417  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4418  * 
4419  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4420  */
4421 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4422 {
4423   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4424   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4425 }
4426
4427 /*!
4428  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4429  * least two its edges intersect each other anywhere except their extremities. An
4430  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4431  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4432  *         cleared before filling in.
4433  *  \param [in] eps - precision.
4434  *  \throw If \a this->getMeshDimension() != 2.
4435  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4436  */
4437 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4438 {
4439   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4440   if(getMeshDimension()!=2)
4441     throw INTERP_KERNEL::Exception(msg);
4442   int spaceDim=getSpaceDimension();
4443   if(spaceDim!=2 && spaceDim!=3)
4444     throw INTERP_KERNEL::Exception(msg);
4445   const mcIdType *conn=_nodal_connec->getConstPointer();
4446   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4447   mcIdType nbOfCells=getNumberOfCells();
4448   std::vector<double> cell2DinS2;
4449   for(mcIdType i=0;i<nbOfCells;i++)
4450     {
4451       mcIdType offset=connI[i];
4452       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4453       if(nbOfNodesForCell<=3)
4454         continue;
4455       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4456       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4457       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4458         cells.push_back(i);
4459       cell2DinS2.clear();
4460     }
4461 }
4462
4463 /*!
4464  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4465  *
4466  * 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.
4467  * 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.
4468  *
4469  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4470  * This convex envelop is computed using Jarvis march algorithm.
4471  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4472  * 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)
4473  * 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.
4474  *
4475  * \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.
4476  * \sa MEDCouplingUMesh::colinearize2D
4477  */
4478 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4479 {
4480   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4481     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4482   checkFullyDefined();
4483   const double *coords=getCoords()->getConstPointer();
4484   mcIdType nbOfCells=getNumberOfCells();
4485   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4486   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4487   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4488   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4489   *workIndexOut=0;
4490   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4491   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4492   std::set<INTERP_KERNEL::NormalizedCellType> types;
4493   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4494   isChanged->alloc(0,1);
4495   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4496     {
4497       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4498       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4499         isChanged->pushBackSilent(i);
4500       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4501       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4502     }
4503   if(isChanged->empty())
4504     return 0;
4505   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4506   _types=types;
4507   return isChanged.retn();
4508 }
4509
4510 /*!
4511  * This method is \b NOT const because it can modify \a this.
4512  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4513  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4514  * \param policy specifies the type of extrusion chosen:
4515  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4516  *   will be repeated to build each level
4517  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4518  *   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
4519  *   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
4520  *   arc.
4521  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4522  */
4523 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4524 {
4525   checkFullyDefined();
4526   mesh1D->checkFullyDefined();
4527   if(!mesh1D->isContiguous1D())
4528     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4529   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4530     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4531   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4532     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4533   if(mesh1D->getMeshDimension()!=1)
4534     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4535   bool isQuad=false;
4536   if(isPresenceOfQuadratic())
4537     {
4538       if(mesh1D->isFullyQuadratic())
4539         isQuad=true;
4540       else
4541         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4542     }
4543   mcIdType oldNbOfNodes(getNumberOfNodes());
4544   MCAuto<DataArrayDouble> newCoords;
4545   switch(policy)
4546   {
4547     case 0:
4548       {
4549         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4550         break;
4551       }
4552     case 1:
4553       {
4554         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4555         break;
4556       }
4557     default:
4558       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4559   }
4560   setCoords(newCoords);
4561   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4562   updateTime();
4563   return ret.retn();
4564 }
4565
4566
4567 /*!
4568  * Checks if \a this mesh is constituted by only quadratic cells.
4569  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4570  *  \throw If the coordinates array is not set.
4571  *  \throw If the nodal connectivity of cells is not defined.
4572  */
4573 bool MEDCouplingUMesh::isFullyQuadratic() const
4574 {
4575   checkFullyDefined();
4576   bool ret=true;
4577   mcIdType nbOfCells=getNumberOfCells();
4578   for(mcIdType i=0;i<nbOfCells && ret;i++)
4579     {
4580       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4581       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4582       ret=cm.isQuadratic();
4583     }
4584   return ret;
4585 }
4586
4587 /*!
4588  * Checks if \a this mesh includes any quadratic cell.
4589  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4590  *  \throw If the coordinates array is not set.
4591  *  \throw If the nodal connectivity of cells is not defined.
4592  */
4593 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4594 {
4595   checkFullyDefined();
4596   bool ret=false;
4597   mcIdType nbOfCells=getNumberOfCells();
4598   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4599     {
4600       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4601       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4602       ret=cm.isQuadratic();
4603     }
4604   return ret;
4605 }
4606
4607 /*!
4608  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4609  * this mesh, it remains unchanged.
4610  *  \throw If the coordinates array is not set.
4611  *  \throw If the nodal connectivity of cells is not defined.
4612  */
4613 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4614 {
4615   checkFullyDefined();
4616   mcIdType nbOfCells=getNumberOfCells();
4617   mcIdType delta=0;
4618   const mcIdType *iciptr=_nodal_connec_index->begin();
4619   for(mcIdType i=0;i<nbOfCells;i++)
4620     {
4621       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4622       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4623       if(cm.isQuadratic())
4624         {
4625           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4626           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4627           if(!cml.isDynamic())
4628             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4629           else
4630             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4631         }
4632     }
4633   if(delta==0)
4634     return ;
4635   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4636   const mcIdType *icptr(_nodal_connec->begin());
4637   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4638   newConnI->alloc(nbOfCells+1,1);
4639   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4640   *ociptr=0;
4641   _types.clear();
4642   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4643     {
4644       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4645       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4646       if(!cm.isQuadratic())
4647         {
4648           _types.insert(type);
4649           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4650           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4651         }
4652       else
4653         {
4654           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4655           _types.insert(typel);
4656           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4657           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4658           if(cml.isDynamic())
4659             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4660           *ocptr++=ToIdType(typel);
4661           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4662           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4663         }
4664     }
4665   setConnectivity(newConn,newConnI,false);
4666 }
4667
4668 /*!
4669  * This method converts all linear cell in \a this to quadratic one.
4670  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4671  * 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)
4672  * 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.
4673  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4674  * end of the existing coordinates.
4675  *
4676  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4677  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4678  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4679  *
4680  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4681  *
4682  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4683  */
4684 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4685 {
4686   DataArrayIdType *conn=0,*connI=0;
4687   DataArrayDouble *coords=0;
4688   std::set<INTERP_KERNEL::NormalizedCellType> types;
4689   checkFullyDefined();
4690   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4691   MCAuto<DataArrayDouble> coordsSafe;
4692   int meshDim=getMeshDimension();
4693   switch(conversionType)
4694   {
4695     case 0:
4696       switch(meshDim)
4697       {
4698         case 1:
4699           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4700           connSafe=conn; connISafe=connI; coordsSafe=coords;
4701           break;
4702         case 2:
4703           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4704           connSafe=conn; connISafe=connI; coordsSafe=coords;
4705           break;
4706         case 3:
4707           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4708           connSafe=conn; connISafe=connI; coordsSafe=coords;
4709           break;
4710         default:
4711           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4712       }
4713       break;
4714         case 1:
4715           {
4716             switch(meshDim)
4717             {
4718               case 1:
4719                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4720                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4721                 break;
4722               case 2:
4723                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4724                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4725                 break;
4726               case 3:
4727                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4728                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4729                 break;
4730               default:
4731                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4732             }
4733             break;
4734           }
4735         default:
4736           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4737   }
4738   setConnectivity(connSafe,connISafe,false);
4739   _types=types;
4740   setCoords(coordsSafe);
4741   return ret.retn();
4742 }
4743
4744 /*!
4745  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4746  * so that the number of cells remains the same. Quadratic faces are converted to
4747  * polygons. This method works only for 2D meshes in
4748  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4749  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4750  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4751  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4752  *         a polylinized edge constituting the input polygon.
4753  *  \throw If the coordinates array is not set.
4754  *  \throw If the nodal connectivity of cells is not defined.
4755  *  \throw If \a this->getMeshDimension() != 2.
4756  *  \throw If \a this->getSpaceDimension() != 2.
4757  */
4758 void MEDCouplingUMesh::tessellate2D(double eps)
4759 {
4760   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4761   if(spaceDim!=2)
4762     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4763   switch(meshDim)
4764     {
4765     case 1:
4766       return tessellate2DCurveInternal(eps);
4767     case 2:
4768       return tessellate2DInternal(eps);
4769     default:
4770       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4771     }
4772 }
4773
4774 #if 0
4775 /*!
4776  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4777  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4778  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4779  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4780  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4781  * This method can be seen as the opposite method of colinearize2D.
4782  * 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
4783  * to avoid to modify the numbering of existing nodes.
4784  *
4785  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4786  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4787  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4788  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4789  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4790  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4791  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4792  *
4793  * \sa buildDescendingConnectivity2
4794  */
4795 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4796                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4797 {
4798   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4799     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4800   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4801   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4802     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4803   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4804     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4805   //DataArrayIdType *out0(0),*outi0(0);
4806   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4807   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4808   //out0s=out0s->buildUnique(); out0s->sort(true);
4809 }
4810 #endif
4811
4812
4813 /*!
4814  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4815  * In addition, returns an array mapping new cells to old ones. <br>
4816  * This method typically increases the number of cells in \a this mesh
4817  * but the number of nodes remains \b unchanged.
4818  * That's why the 3D splitting policies
4819  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4820  *  \param [in] policy - specifies a pattern used for splitting.
4821  * The semantic of \a policy is:
4822  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4823  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4824  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4825  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4826  *
4827  *
4828  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4829  *          an id of old cell producing it. The caller is to delete this array using
4830  *         decrRef() as it is no more needed.
4831  *
4832  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4833  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4834  *          and \a this->getMeshDimension() != 3.
4835  *  \throw If \a policy is not one of the four discussed above.
4836  *  \throw If the nodal connectivity of cells is not defined.
4837  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4838  */
4839 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4840 {
4841   switch(policy)
4842   {
4843     case 0:
4844       return simplexizePol0();
4845     case 1:
4846       return simplexizePol1();
4847     case INTERP_KERNEL::PLANAR_FACE_5:
4848         return simplexizePlanarFace5();
4849     case INTERP_KERNEL::PLANAR_FACE_6:
4850         return simplexizePlanarFace6();
4851     default:
4852       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)");
4853   }
4854 }
4855
4856 /*!
4857  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4858  * - 1D: INTERP_KERNEL::NORM_SEG2
4859  * - 2D: INTERP_KERNEL::NORM_TRI3
4860  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4861  *
4862  * This method is useful for users that need to use P1 field services as
4863  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4864  * All these methods need mesh support containing only simplex cells.
4865  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4866  *  \throw If the coordinates array is not set.
4867  *  \throw If the nodal connectivity of cells is not defined.
4868  *  \throw If \a this->getMeshDimension() < 1.
4869  */
4870 bool MEDCouplingUMesh::areOnlySimplexCells() const
4871 {
4872   checkFullyDefined();
4873   int mdim=getMeshDimension();
4874   if(mdim<1 || mdim>3)
4875     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4876   mcIdType nbCells=getNumberOfCells();
4877   const mcIdType *conn=_nodal_connec->begin();
4878   const mcIdType *connI=_nodal_connec_index->begin();
4879   for(mcIdType i=0;i<nbCells;i++)
4880     {
4881       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4882       if(!cm.isSimplex())
4883         return false;
4884     }
4885   return true;
4886 }
4887
4888
4889
4890 /*!
4891  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4892  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4893  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4894  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4895  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4896  * so it can be useful to call mergeNodes() before calling this method.
4897  *  \throw If \a this->getMeshDimension() <= 1.
4898  *  \throw If the coordinates array is not set.
4899  *  \throw If the nodal connectivity of cells is not defined.
4900  */
4901 void MEDCouplingUMesh::convertDegeneratedCells()
4902 {
4903   checkFullyDefined();
4904   if(getMeshDimension()<=1)
4905     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4906   mcIdType nbOfCells=getNumberOfCells();
4907   if(nbOfCells<1)
4908     return ;
4909   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4910   mcIdType *conn=_nodal_connec->getPointer();
4911   mcIdType *index=_nodal_connec_index->getPointer();
4912   mcIdType posOfCurCell=0;
4913   mcIdType newPos=0;
4914   mcIdType lgthOfCurCell;
4915   for(mcIdType i=0;i<nbOfCells;i++)
4916     {
4917       lgthOfCurCell=index[i+1]-posOfCurCell;
4918       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4919       mcIdType newLgth;
4920       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4921                                                                                                      conn+newPos+1,newLgth);
4922       conn[newPos]=newType;
4923       newPos+=newLgth+1;
4924       posOfCurCell=index[i+1];
4925       index[i+1]=newPos;
4926     }
4927   if(newPos!=initMeshLgth)
4928     _nodal_connec->reAlloc(newPos);
4929   computeTypes();
4930 }
4931
4932 /*!
4933  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4934  * A cell is flat in the following cases:
4935  *   - for a linear cell, all points in the connectivity are equal
4936  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4937  *   identical quadratic points
4938  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4939  *      this array using decrRef() as it is no more needed.
4940  */
4941 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4942 {
4943   checkFullyDefined();
4944   if(getMeshDimension()<=1)
4945     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4946   mcIdType nbOfCells=getNumberOfCells();
4947   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4948   if(nbOfCells<1)
4949     return ret.retn();
4950   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4951   mcIdType *conn=_nodal_connec->getPointer();
4952   mcIdType *index=_nodal_connec_index->getPointer();
4953   mcIdType posOfCurCell=0;
4954   mcIdType newPos=0;
4955   mcIdType lgthOfCurCell, nbDelCells(0);
4956   for(mcIdType i=0;i<nbOfCells;i++)
4957     {
4958       lgthOfCurCell=index[i+1]-posOfCurCell;
4959       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4960       mcIdType newLgth;
4961       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4962                                                                                                      conn+newPos+1,newLgth);
4963       // Shall we delete the cell if it is completely degenerated:
4964       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4965       if (delCell)
4966         {
4967           nbDelCells++;
4968           ret->pushBackSilent(i);
4969         }
4970       else   //if the cell is to be deleted, simply stay at the same place
4971         {
4972           conn[newPos]=newType;
4973           newPos+=newLgth+1;
4974         }
4975       posOfCurCell=index[i+1];
4976       index[i+1-nbDelCells]=newPos;
4977     }
4978   if(newPos!=initMeshLgth)
4979     _nodal_connec->reAlloc(newPos);
4980   const mcIdType nCellDel=ret->getNumberOfTuples();
4981   if (nCellDel)
4982     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4983   computeTypes();
4984   return ret.retn();
4985 }
4986
4987 /*!
4988  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4989  * Only connectivity is considered here.
4990  */
4991 bool MEDCouplingUMesh::removeDegenerated1DCells()
4992 {
4993   checkConnectivityFullyDefined();
4994   if(getMeshDimension()!=1)
4995     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4996   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4997   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4998   {
4999     for(std::size_t i=0;i<nbCells;i++)
5000       {
5001         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5002         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5003           {
5004             if(conn[conni[i]+1]!=conn[conni[i]+2])
5005               {
5006                 newSize++;
5007                 newSize2+=conni[i+1]-conni[i];
5008               }
5009           }
5010         else
5011           {
5012             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5013             throw INTERP_KERNEL::Exception(oss.str());
5014           }
5015       }
5016   }
5017   if(newSize==nbCells)//no cells has been removed -> do nothing
5018     return false;
5019   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5020   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5021   for(std::size_t i=0;i<nbCells;i++)
5022     {
5023       if(conn[conni[i]+1]!=conn[conni[i]+2])
5024         {
5025           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5026           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5027           newConnIPtr++;
5028         }
5029     }
5030   setConnectivity(newConn,newConnI,true);
5031   return true;
5032 }
5033
5034 /*!
5035  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5036  * A cell is considered to be oriented correctly if an angle between its
5037  * normal vector and a given vector is less than \c PI / \c 2.
5038  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5039  *         cells.
5040  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5041  *         checked.
5042  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5043  *         is not cleared before filling in.
5044  *  \throw If \a this->getMeshDimension() != 2.
5045  *  \throw If \a this->getSpaceDimension() != 3.
5046  *
5047  *  \if ENABLE_EXAMPLES
5048  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5049  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5050  *  \endif
5051  */
5052 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5053 {
5054   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5055     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5056   mcIdType nbOfCells=getNumberOfCells();
5057   const mcIdType *conn=_nodal_connec->begin();
5058   const mcIdType *connI=_nodal_connec_index->begin();
5059   const double *coordsPtr=_coords->begin();
5060   for(mcIdType i=0;i<nbOfCells;i++)
5061     {
5062       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5063       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5064         {
5065           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5066           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5067             cells.push_back(i);
5068         }
5069     }
5070 }
5071
5072 /*!
5073  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5074  * considered to be oriented correctly if an angle between its normal vector and a
5075  * given vector is less than \c PI / \c 2.
5076  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5077  *         cells.
5078  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5079  *         checked.
5080  *  \throw If \a this->getMeshDimension() != 2.
5081  *  \throw If \a this->getSpaceDimension() != 3.
5082  *
5083  *  \if ENABLE_EXAMPLES
5084  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5085  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5086  *  \endif
5087  *
5088  *  \sa changeOrientationOfCells
5089  */
5090 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5091 {
5092   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5093     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5094   mcIdType nbOfCells=getNumberOfCells();
5095   mcIdType *conn(_nodal_connec->getPointer());
5096   const mcIdType *connI(_nodal_connec_index->begin());
5097   const double *coordsPtr(_coords->begin());
5098   bool isModified(false);
5099   for(mcIdType i=0;i<nbOfCells;i++)
5100     {
5101       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5102       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5103         {
5104           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5105           bool isQuadratic(cm.isQuadratic());
5106           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5107             {
5108               isModified=true;
5109               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5110             }
5111         }
5112     }
5113   if(isModified)
5114     _nodal_connec->declareAsNew();
5115   updateTime();
5116 }
5117
5118 /*!
5119  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5120  *
5121  * \sa orientCorrectly2DCells
5122  */
5123 void MEDCouplingUMesh::changeOrientationOfCells()
5124 {
5125   int mdim(getMeshDimension());
5126   if(mdim!=2 && mdim!=1)
5127     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5128   mcIdType nbOfCells=getNumberOfCells();
5129   mcIdType *conn(_nodal_connec->getPointer());
5130   const mcIdType *connI(_nodal_connec_index->begin());
5131   if(mdim==2)
5132     {//2D
5133       for(mcIdType i=0;i<nbOfCells;i++)
5134         {
5135           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5136           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5137           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5138         }
5139     }
5140   else
5141     {//1D
5142       for(mcIdType i=0;i<nbOfCells;i++)
5143         {
5144           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5145           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5146           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5147         }
5148     }
5149 }
5150
5151 /*!
5152  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5153  * oriented facets. The normal vector of the facet should point out of the cell.
5154  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5155  *         is not cleared before filling in.
5156  *  \throw If \a this->getMeshDimension() != 3.
5157  *  \throw If \a this->getSpaceDimension() != 3.
5158  *  \throw If the coordinates array is not set.
5159  *  \throw If the nodal connectivity of cells is not defined.
5160  *
5161  *  \if ENABLE_EXAMPLES
5162  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5163  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5164  *  \endif
5165  */
5166 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5167 {
5168   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5169     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5170   mcIdType nbOfCells=getNumberOfCells();
5171   const mcIdType *conn=_nodal_connec->begin();
5172   const mcIdType *connI=_nodal_connec_index->begin();
5173   const double *coordsPtr=_coords->begin();
5174   for(mcIdType i=0;i<nbOfCells;i++)
5175     {
5176       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5177       if(type==INTERP_KERNEL::NORM_POLYHED)
5178         {
5179           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5180             cells.push_back(i);
5181         }
5182     }
5183 }
5184
5185 /*!
5186  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5187  * out of the cell.
5188  *  \throw If \a this->getMeshDimension() != 3.
5189  *  \throw If \a this->getSpaceDimension() != 3.
5190  *  \throw If the coordinates array is not set.
5191  *  \throw If the nodal connectivity of cells is not defined.
5192  *  \throw If the reparation fails.
5193  *
5194  *  \if ENABLE_EXAMPLES
5195  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5196  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5197  *  \endif
5198  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5199  */
5200 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5201 {
5202   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5203     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5204   mcIdType nbOfCells=getNumberOfCells();
5205   mcIdType *conn=_nodal_connec->getPointer();
5206   const mcIdType *connI=_nodal_connec_index->begin();
5207   const double *coordsPtr=_coords->begin();
5208   for(mcIdType i=0;i<nbOfCells;i++)
5209     {
5210       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5211       if(type==INTERP_KERNEL::NORM_POLYHED)
5212         {
5213           try
5214           {
5215               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5216                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5217           }
5218           catch(INTERP_KERNEL::Exception& e)
5219           {
5220               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5221               throw INTERP_KERNEL::Exception(oss.str());
5222           }
5223         }
5224     }
5225   updateTime();
5226 }
5227
5228 /*!
5229  * This method invert orientation of all cells in \a this.
5230  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5231  * This method only operates on the connectivity so coordinates are not touched at all.
5232  */
5233 void MEDCouplingUMesh::invertOrientationOfAllCells()
5234 {
5235   checkConnectivityFullyDefined();
5236   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5237   mcIdType *conn(_nodal_connec->getPointer());
5238   const mcIdType *conni(_nodal_connec_index->begin());
5239   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5240     {
5241       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5242       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5243       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5244         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5245     }
5246   updateTime();
5247 }
5248
5249 /*!
5250  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5251  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5252  * according to which the first facet of the cell should be oriented to have the normal vector
5253  * pointing out of cell.
5254  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5255  *         cells. The caller is to delete this array using decrRef() as it is no more
5256  *         needed.
5257  *  \throw If \a this->getMeshDimension() != 3.
5258  *  \throw If \a this->getSpaceDimension() != 3.
5259  *  \throw If the coordinates array is not set.
5260  *  \throw If the nodal connectivity of cells is not defined.
5261  *
5262  *  \if ENABLE_EXAMPLES
5263  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5264  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5265  *  \endif
5266  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5267  */
5268 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5269 {
5270   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5271   if(getMeshDimension()!=3)
5272     throw INTERP_KERNEL::Exception(msg);
5273   int spaceDim=getSpaceDimension();
5274   if(spaceDim!=3)
5275     throw INTERP_KERNEL::Exception(msg);
5276   //
5277   mcIdType nbOfCells=getNumberOfCells();
5278   mcIdType *conn=_nodal_connec->getPointer();
5279   const mcIdType *connI=_nodal_connec_index->begin();
5280   const double *coo=getCoords()->begin();
5281   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5282   for(mcIdType i=0;i<nbOfCells;i++)
5283     {
5284       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5285       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5286         {
5287           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5288             {
5289               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5290               cells->pushBackSilent(i);
5291             }
5292         }
5293     }
5294   return cells.retn();
5295 }
5296
5297 /*!
5298  * This method is a faster method to correct orientation of all 3D cells in \a this.
5299  * 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.
5300  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5301  *
5302  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5303  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5304  */
5305 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5306 {
5307   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5308     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5309   mcIdType nbOfCells=getNumberOfCells();
5310   mcIdType *conn=_nodal_connec->getPointer();
5311   const mcIdType *connI=_nodal_connec_index->begin();
5312   const double *coordsPtr=_coords->begin();
5313   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5314   for(mcIdType i=0;i<nbOfCells;i++)
5315     {
5316       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5317       switch(type)
5318       {
5319         case INTERP_KERNEL::NORM_TETRA4:
5320           {
5321             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5322               {
5323                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5324                 ret->pushBackSilent(i);
5325               }
5326             break;
5327           }
5328         case INTERP_KERNEL::NORM_PYRA5:
5329           {
5330             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5331               {
5332                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5333                 ret->pushBackSilent(i);
5334               }
5335             break;
5336           }
5337         case INTERP_KERNEL::NORM_PENTA6:
5338         case INTERP_KERNEL::NORM_HEXA8:
5339         case INTERP_KERNEL::NORM_HEXGP12:
5340           {
5341             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5342               {
5343                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5344                 ret->pushBackSilent(i);
5345               }
5346             break;
5347           }
5348         case INTERP_KERNEL::NORM_POLYHED:
5349           {
5350             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5351               {
5352                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5353                 ret->pushBackSilent(i);
5354               }
5355             break;
5356           }
5357         default:
5358           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 !");
5359       }
5360     }
5361   updateTime();
5362   return ret.retn();
5363 }
5364
5365 /*!
5366  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5367  * If it is not the case an exception will be thrown.
5368  * This method is fast because the first cell of \a this is used to compute the plane.
5369  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5370  * \param pos output of size at least 3 used to store a point owned of searched plane.
5371  */
5372 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5373 {
5374   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5375     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5376   const mcIdType *conn=_nodal_connec->begin();
5377   const mcIdType *connI=_nodal_connec_index->begin();
5378   const double *coordsPtr=_coords->begin();
5379   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5380   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5381 }
5382
5383 /*!
5384  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5385  * cells. Currently cells of the following types are treated:
5386  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5387  * For a cell of other type an exception is thrown.
5388  * Space dimension of a 2D mesh can be either 2 or 3.
5389  * The Edge Ratio of a cell \f$t\f$ is:
5390  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5391  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5392  *  the smallest edge lengths of \f$t\f$.
5393  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5394  *          cells and one time, lying on \a this mesh. The caller is to delete this
5395  *          field using decrRef() as it is no more needed.
5396  *  \throw If the coordinates array is not set.
5397  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5398  *  \throw If the connectivity data array has more than one component.
5399  *  \throw If the connectivity data array has a named component.
5400  *  \throw If the connectivity index data array has more than one component.
5401  *  \throw If the connectivity index data array has a named component.
5402  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5403  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5404  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5405  */
5406 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5407 {
5408   checkConsistencyLight();
5409   int spaceDim=getSpaceDimension();
5410   int meshDim=getMeshDimension();
5411   if(spaceDim!=2 && spaceDim!=3)
5412     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5413   if(meshDim!=2 && meshDim!=3)
5414     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5415   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5416   ret->setMesh(this);
5417   mcIdType nbOfCells=getNumberOfCells();
5418   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5419   arr->alloc(nbOfCells,1);
5420   double *pt=arr->getPointer();
5421   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5422   const mcIdType *conn=_nodal_connec->begin();
5423   const mcIdType *connI=_nodal_connec_index->begin();
5424   const double *coo=_coords->begin();
5425   double tmp[12];
5426   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5427     {
5428       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5429       switch(t)
5430       {
5431         case INTERP_KERNEL::NORM_TRI3:
5432           {
5433             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5434             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5435             break;
5436           }
5437         case INTERP_KERNEL::NORM_QUAD4:
5438           {
5439             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5440             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5441             break;
5442           }
5443         case INTERP_KERNEL::NORM_TETRA4:
5444           {
5445             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5446             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5447             break;
5448           }
5449         default:
5450           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5451       }
5452       conn+=connI[i+1]-connI[i];
5453     }
5454   ret->setName("EdgeRatio");
5455   ret->synchronizeTimeWithSupport();
5456   return ret.retn();
5457 }
5458
5459 /*!
5460  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5461  * cells. Currently cells of the following types are treated:
5462  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5463  * For a cell of other type an exception is thrown.
5464  * Space dimension of a 2D mesh can be either 2 or 3.
5465  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5466  *          cells and one time, lying on \a this mesh. The caller is to delete this
5467  *          field using decrRef() as it is no more needed.
5468  *  \throw If the coordinates array is not set.
5469  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5470  *  \throw If the connectivity data array has more than one component.
5471  *  \throw If the connectivity data array has a named component.
5472  *  \throw If the connectivity index data array has more than one component.
5473  *  \throw If the connectivity index data array has a named component.
5474  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5475  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5476  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5477  */
5478 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5479 {
5480   checkConsistencyLight();
5481   int spaceDim=getSpaceDimension();
5482   int meshDim=getMeshDimension();
5483   if(spaceDim!=2 && spaceDim!=3)
5484     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5485   if(meshDim!=2 && meshDim!=3)
5486     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5487   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5488   ret->setMesh(this);
5489   mcIdType nbOfCells=getNumberOfCells();
5490   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5491   arr->alloc(nbOfCells,1);
5492   double *pt=arr->getPointer();
5493   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5494   const mcIdType *conn=_nodal_connec->begin();
5495   const mcIdType *connI=_nodal_connec_index->begin();
5496   const double *coo=_coords->begin();
5497   double tmp[12];
5498   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5499     {
5500       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5501       switch(t)
5502       {
5503         case INTERP_KERNEL::NORM_TRI3:
5504           {
5505             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5506             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5507             break;
5508           }
5509         case INTERP_KERNEL::NORM_QUAD4:
5510           {
5511             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5512             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5513             break;
5514           }
5515         case INTERP_KERNEL::NORM_TETRA4:
5516           {
5517             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5518             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5519             break;
5520           }
5521         default:
5522           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5523       }
5524       conn+=connI[i+1]-connI[i];
5525     }
5526   ret->setName("AspectRatio");
5527   ret->synchronizeTimeWithSupport();
5528   return ret.retn();
5529 }
5530
5531 /*!
5532  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5533  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5534  * in 3D space. Currently only cells of the following types are
5535  * treated: INTERP_KERNEL::NORM_QUAD4.
5536  * For a cell of other type an exception is thrown.
5537  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5538  * Defining
5539  * \f$t=\vec{da}\times\vec{ab}\f$,
5540  * \f$u=\vec{ab}\times\vec{bc}\f$
5541  * \f$v=\vec{bc}\times\vec{cd}\f$
5542  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5543  *  \f[
5544  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5545  *  \f]
5546  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5547  *          cells and one time, lying on \a this mesh. The caller is to delete this
5548  *          field using decrRef() as it is no more needed.
5549  *  \throw If the coordinates array is not set.
5550  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5551  *  \throw If the connectivity data array has more than one component.
5552  *  \throw If the connectivity data array has a named component.
5553  *  \throw If the connectivity index data array has more than one component.
5554  *  \throw If the connectivity index data array has a named component.
5555  *  \throw If \a this->getMeshDimension() != 2.
5556  *  \throw If \a this->getSpaceDimension() != 3.
5557  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5558  */
5559 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5560 {
5561   checkConsistencyLight();
5562   int spaceDim=getSpaceDimension();
5563   int meshDim=getMeshDimension();
5564   if(spaceDim!=3)
5565     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5566   if(meshDim!=2)
5567     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5568   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5569   ret->setMesh(this);
5570   mcIdType nbOfCells=getNumberOfCells();
5571   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5572   arr->alloc(nbOfCells,1);
5573   double *pt=arr->getPointer();
5574   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5575   const mcIdType *conn=_nodal_connec->begin();
5576   const mcIdType *connI=_nodal_connec_index->begin();
5577   const double *coo=_coords->begin();
5578   double tmp[12];
5579   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5580     {
5581       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5582       switch(t)
5583       {
5584         case INTERP_KERNEL::NORM_QUAD4:
5585           {
5586             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5587             *pt=INTERP_KERNEL::quadWarp(tmp);
5588             break;
5589           }
5590         default:
5591           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5592       }
5593       conn+=connI[i+1]-connI[i];
5594     }
5595   ret->setName("Warp");
5596   ret->synchronizeTimeWithSupport();
5597   return ret.retn();
5598 }
5599
5600
5601 /*!
5602  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5603  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5604  * treated: INTERP_KERNEL::NORM_QUAD4.
5605  * The skew is computed as follow for a quad with points (a,b,c,d): let
5606  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5607  * then the skew is computed as:
5608  *  \f[
5609  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5610  *  \f]
5611  *
5612  * For a cell of other type an exception is thrown.
5613  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5614  *          cells and one time, lying on \a this mesh. The caller is to delete this
5615  *          field using decrRef() as it is no more needed.
5616  *  \throw If the coordinates array is not set.
5617  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5618  *  \throw If the connectivity data array has more than one component.
5619  *  \throw If the connectivity data array has a named component.
5620  *  \throw If the connectivity index data array has more than one component.
5621  *  \throw If the connectivity index data array has a named component.
5622  *  \throw If \a this->getMeshDimension() != 2.
5623  *  \throw If \a this->getSpaceDimension() != 3.
5624  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5625  */
5626 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5627 {
5628   checkConsistencyLight();
5629   int spaceDim=getSpaceDimension();
5630   int meshDim=getMeshDimension();
5631   if(spaceDim!=3)
5632     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5633   if(meshDim!=2)
5634     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5635   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5636   ret->setMesh(this);
5637   mcIdType nbOfCells=getNumberOfCells();
5638   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5639   arr->alloc(nbOfCells,1);
5640   double *pt=arr->getPointer();
5641   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5642   const mcIdType *conn=_nodal_connec->begin();
5643   const mcIdType *connI=_nodal_connec_index->begin();
5644   const double *coo=_coords->begin();
5645   double tmp[12];
5646   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5647     {
5648       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5649       switch(t)
5650       {
5651         case INTERP_KERNEL::NORM_QUAD4:
5652           {
5653             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5654             *pt=INTERP_KERNEL::quadSkew(tmp);
5655             break;
5656           }
5657         default:
5658           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5659       }
5660       conn+=connI[i+1]-connI[i];
5661     }
5662   ret->setName("Skew");
5663   ret->synchronizeTimeWithSupport();
5664   return ret.retn();
5665 }
5666
5667 /*!
5668  * 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.
5669  *
5670  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5671  *
5672  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5673  */
5674 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5675 {
5676   checkConsistencyLight();
5677   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5678   ret->setMesh(this);
5679   std::set<INTERP_KERNEL::NormalizedCellType> types;
5680   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5681   int spaceDim(getSpaceDimension());
5682   mcIdType nbCells(getNumberOfCells());
5683   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5684   arr->alloc(nbCells,1);
5685   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5686     {
5687       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5688       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5689       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5690     }
5691   ret->setArray(arr);
5692   ret->setName("Diameter");
5693   return ret.retn();
5694 }
5695
5696 /*!
5697  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5698  *
5699  * \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)
5700  *                         For all other cases this input parameter is ignored.
5701  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5702  *
5703  * \throw If \a this is not fully set (coordinates and connectivity).
5704  * \throw If a cell in \a this has no valid nodeId.
5705  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5706  */
5707 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5708 {
5709   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5710   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.
5711     return getBoundingBoxForBBTreeFast();
5712   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5713     {
5714       bool presenceOfQuadratic(false);
5715       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5716         {
5717           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5718           if(cm.isQuadratic())
5719             presenceOfQuadratic=true;
5720         }
5721       if(!presenceOfQuadratic)
5722         return getBoundingBoxForBBTreeFast();
5723       if(mDim==2 && sDim==2)
5724         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5725       else
5726         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5727     }
5728   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) !");
5729 }
5730
5731 /*!
5732  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5733  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5734  *
5735  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5736  *
5737  * \throw If \a this is not fully set (coordinates and connectivity).
5738  * \throw If a cell in \a this has no valid nodeId.
5739  */
5740 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5741 {
5742   checkFullyDefined();
5743   int spaceDim(getSpaceDimension());
5744   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5745   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5746   double *bbox(ret->getPointer());
5747   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5748     {
5749       bbox[2*i]=std::numeric_limits<double>::max();
5750       bbox[2*i+1]=-std::numeric_limits<double>::max();
5751     }
5752   const double *coordsPtr(_coords->begin());
5753   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5754   for(mcIdType i=0;i<nbOfCells;i++)
5755     {
5756       mcIdType offset=connI[i]+1;
5757       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5758       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5759         {
5760           mcIdType nodeId=conn[offset+j];
5761           if(nodeId>=0 && nodeId<nbOfNodes)
5762             {
5763               for(int k=0;k<spaceDim;k++)
5764                 {
5765                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5766                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5767                 }
5768               kk++;
5769             }
5770         }
5771       if(kk==0)
5772         {
5773           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5774           throw INTERP_KERNEL::Exception(oss.str());
5775         }
5776     }
5777   return ret.retn();
5778 }
5779
5780 /*!
5781  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5782  * useful for 2D meshes having quadratic cells
5783  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5784  * the two extremities of the arc of circle).
5785  *
5786  * \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)
5787  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5788  * \throw If \a this is not fully defined.
5789  * \throw If \a this is not a mesh with meshDimension equal to 2.
5790  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5791  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5792  */
5793 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5794 {
5795   checkFullyDefined();
5796   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5797
5798   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5799   mcIdType nbOfCells=getNumberOfCells();
5800   if(spaceDim!=2 || mDim!=2)
5801     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!");
5802   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5803   double *bbox(ret->getPointer());
5804   const double *coords(_coords->begin());
5805   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5806   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5807     {
5808       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5809       mcIdType sz(connI[1]-connI[0]-1);
5810       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5811       INTERP_KERNEL::QuadraticPolygon *pol(0);
5812       for(mcIdType j=0;j<sz;j++)
5813         {
5814           mcIdType nodeId(conn[*connI+1+j]);
5815           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5816         }
5817       if(!cm.isQuadratic())
5818         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5819       else
5820         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5821       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5822       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5823     }
5824   return ret.retn();
5825 }
5826
5827 /*!
5828  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5829  * useful for 2D meshes having quadratic cells
5830  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5831  * the two extremities of the arc of circle).
5832  *
5833  * \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)
5834  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5835  * \throw If \a this is not fully defined.
5836  * \throw If \a this is not a mesh with meshDimension equal to 1.
5837  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5838  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5839  */
5840 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5841 {
5842   checkFullyDefined();
5843   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5844   mcIdType nbOfCells=getNumberOfCells();
5845   if(spaceDim!=2 || mDim!=1)
5846     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!");
5847   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5848   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5849   double *bbox(ret->getPointer());
5850   const double *coords(_coords->begin());
5851   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5852   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5853     {
5854       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5855       mcIdType sz(connI[1]-connI[0]-1);
5856       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5857       INTERP_KERNEL::Edge *edge(0);
5858       for(mcIdType j=0;j<sz;j++)
5859         {
5860           mcIdType nodeId(conn[*connI+1+j]);
5861           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5862         }
5863       if(!cm.isQuadratic())
5864         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5865       else
5866         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5867       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5868       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5869     }
5870   return ret.retn();
5871 }
5872
5873 /// @cond INTERNAL
5874
5875 namespace MEDCouplingImpl
5876 {
5877   class ConnReader
5878   {
5879   public:
5880     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5881     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5882   private:
5883     const mcIdType *_conn;
5884     mcIdType _val;
5885   };
5886
5887   class ConnReader2
5888   {
5889   public:
5890     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5891     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5892   private:
5893     const mcIdType *_conn;
5894     mcIdType _val;
5895   };
5896 }
5897
5898 /// @endcond
5899
5900 /*!
5901  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5902  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5903  * \a this is composed in cell types.
5904  * The returned array is of size 3*n where n is the number of different types present in \a this.
5905  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5906  * This parameter is kept only for compatibility with other method listed above.
5907  */
5908 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5909 {
5910   checkConnectivityFullyDefined();
5911   const mcIdType *conn=_nodal_connec->begin();
5912   const mcIdType *connI=_nodal_connec_index->begin();
5913   const mcIdType *work=connI;
5914   mcIdType nbOfCells=getNumberOfCells();
5915   std::size_t n=getAllGeoTypes().size();
5916   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5917   std::set<INTERP_KERNEL::NormalizedCellType> types;
5918   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5919     {
5920       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5921       if(types.find(typ)!=types.end())
5922         {
5923           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5924           oss << " is not contiguous !";
5925           throw INTERP_KERNEL::Exception(oss.str());
5926         }
5927       types.insert(typ);
5928       ret[3*i]=typ;
5929       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5930       ret[3*i+1]=ToIdType(std::distance(work,work2));
5931       work=work2;
5932     }
5933   return ret;
5934 }
5935
5936 /*!
5937  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5938  * only for types cell, type node is not managed.
5939  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5940  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5941  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5942  * If 2 or more same geometric type is in \a code and exception is thrown too.
5943  *
5944  * This method firstly checks
5945  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5946  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5947  * an exception is thrown too.
5948  *
5949  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5950  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5951  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5952  */
5953 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5954 {
5955   if(code.empty())
5956     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5957   std::size_t sz=code.size();
5958   std::size_t n=sz/3;
5959   if(sz%3!=0)
5960     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5961   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5962   mcIdType nb=0;
5963   bool isNoPflUsed=true;
5964   for(std::size_t i=0;i<n;i++)
5965     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5966       {
5967         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5968         nb+=code[3*i+1];
5969         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5970           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5971         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5972       }
5973   if(types.size()!=n)
5974     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5975   if(isNoPflUsed)
5976     {
5977       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5978         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5979       if(types.size()==_types.size())
5980         return 0;
5981     }
5982   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5983   ret->alloc(nb,1);
5984   mcIdType *retPtr=ret->getPointer();
5985   const mcIdType *connI=_nodal_connec_index->begin();
5986   const mcIdType *conn=_nodal_connec->begin();
5987   mcIdType nbOfCells=getNumberOfCells();
5988   const mcIdType *i=connI;
5989   int kk=0;
5990   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5991     {
5992       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5993       mcIdType offset=ToIdType(std::distance(connI,i));
5994       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5995       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5996       if(code[3*kk+2]==-1)
5997         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5998           *retPtr++=k+offset;
5999       else
6000         {
6001           mcIdType idInIdsPerType=code[3*kk+2];
6002           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6003             {
6004               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6005               if(zePfl)
6006                 {
6007                   zePfl->checkAllocated();
6008                   if(zePfl->getNumberOfComponents()==1)
6009                     {
6010                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6011                         {
6012                           if(*k>=0 && *k<nbOfCellsOfCurType)
6013                             *retPtr=(*k)+offset;
6014                           else
6015                             {
6016                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6017                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6018                               throw INTERP_KERNEL::Exception(oss.str());
6019                             }
6020                         }
6021                     }
6022                   else
6023                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6024                 }
6025               else
6026                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6027             }
6028           else
6029             {
6030               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6031               oss << " should be in [0," << idsPerType.size() << ") !";
6032               throw INTERP_KERNEL::Exception(oss.str());
6033             }
6034         }
6035       i=j;
6036     }
6037   return ret.retn();
6038 }
6039
6040 /*!
6041  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6042  * 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.
6043  * 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.
6044  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6045  *
6046  * \param [in] profile list of IDs constituing the profile
6047  * \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.
6048  * \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,
6049  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6050  * \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.
6051  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6052  * \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
6053  */
6054 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6055 {
6056   if(!profile)
6057     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6058   if(profile->getNumberOfComponents()!=1)
6059     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6060   checkConnectivityFullyDefined();
6061   const mcIdType *conn=_nodal_connec->begin();
6062   const mcIdType *connI=_nodal_connec_index->begin();
6063   mcIdType nbOfCells=getNumberOfCells();
6064   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6065   std::vector<mcIdType> typeRangeVals(1);
6066   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6067     {
6068       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6069       if(std::find(types.begin(),types.end(),curType)!=types.end())
6070         {
6071           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6072         }
6073       types.push_back(curType);
6074       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6075       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6076     }
6077   //
6078   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6079   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6080   MCAuto<DataArrayIdType> tmp0=castArr;
6081   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6082   MCAuto<DataArrayIdType> tmp2=castsPresent;
6083   //
6084   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6085   code.resize(3*nbOfCastsFinal);
6086   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6087   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6088   for(mcIdType i=0;i<nbOfCastsFinal;i++)
6089     {
6090       mcIdType castId=castsPresent->getIJ(i,0);
6091       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6092       idsInPflPerType2.push_back(tmp3);
6093       code[3*i]=ToIdType(types[castId]);
6094       code[3*i+1]=tmp3->getNumberOfTuples();
6095       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6096       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6097         {
6098           tmp4->copyStringInfoFrom(*profile);
6099           idsPerType2.push_back(tmp4);
6100           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6101         }
6102       else
6103         {
6104           code[3*i+2]=-1;
6105         }
6106     }
6107   std::size_t sz2=idsInPflPerType2.size();
6108   idsInPflPerType.resize(sz2);
6109   for(std::size_t i=0;i<sz2;i++)
6110     {
6111       DataArrayIdType *locDa=idsInPflPerType2[i];
6112       locDa->incrRef();
6113       idsInPflPerType[i]=locDa;
6114     }
6115   std::size_t sz=idsPerType2.size();
6116   idsPerType.resize(sz);
6117   for(std::size_t i=0;i<sz;i++)
6118     {
6119       DataArrayIdType *locDa=idsPerType2[i];
6120       locDa->incrRef();
6121       idsPerType[i]=locDa;
6122     }
6123 }
6124
6125 /*!
6126  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6127  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6128  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6129  * 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.
6130  */
6131 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6132 {
6133   checkFullyDefined();
6134   nM1LevMesh->checkFullyDefined();
6135   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6136     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6137   if(_coords!=nM1LevMesh->getCoords())
6138     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6139   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6140   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6141   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6142   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6143   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6144   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6145   tmp->setConnectivity(tmp0,tmp1);
6146   tmp->renumberCells(ret0->begin(),false);
6147   revDesc=tmp->getNodalConnectivity();
6148   revDescIndx=tmp->getNodalConnectivityIndex();
6149   DataArrayIdType *ret=0;
6150   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6151     {
6152       mcIdType tmp2;
6153       ret->getMaxValue(tmp2);
6154       ret->decrRef();
6155       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6156       throw INTERP_KERNEL::Exception(oss.str());
6157     }
6158   nM1LevMeshIds=ret;
6159   //
6160   revDesc->incrRef();
6161   revDescIndx->incrRef();
6162   ret1->incrRef();
6163   ret0->incrRef();
6164   meshnM1Old2New=ret0;
6165   return ret1;
6166 }
6167
6168 /*!
6169  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6170  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6171  * in "Old to New" mode.
6172  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6173  *          this array using decrRef() as it is no more needed.
6174  *  \throw If the nodal connectivity of cells is not defined.
6175  */
6176 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6177 {
6178   checkConnectivityFullyDefined();
6179   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6180   renumberCells(ret->begin(),false);
6181   return ret.retn();
6182 }
6183
6184 /*!
6185  * This methods checks that cells are sorted by their types.
6186  * This method makes asumption (no check) that connectivity is correctly set before calling.
6187  */
6188 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6189 {
6190   checkFullyDefined();
6191   const mcIdType *conn=_nodal_connec->begin();
6192   const mcIdType *connI=_nodal_connec_index->begin();
6193   mcIdType nbOfCells=getNumberOfCells();
6194   std::set<INTERP_KERNEL::NormalizedCellType> types;
6195   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6196     {
6197       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6198       if(types.find(curType)!=types.end())
6199         return false;
6200       types.insert(curType);
6201       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6202     }
6203   return true;
6204 }
6205
6206 /*!
6207  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6208  * The geometric type order is specified by MED file.
6209  *
6210  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6211  */
6212 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6213 {
6214   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6215 }
6216
6217 /*!
6218  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6219  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6220  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6221  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6222  */
6223 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6224 {
6225   checkFullyDefined();
6226   const mcIdType *conn=_nodal_connec->begin();
6227   const mcIdType *connI=_nodal_connec_index->begin();
6228   mcIdType nbOfCells=getNumberOfCells();
6229   if(nbOfCells==0)
6230     return true;
6231   mcIdType lastPos=-1;
6232   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6233   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6234     {
6235       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6236       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6237       if(isTypeExists!=orderEnd)
6238         {
6239           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6240           if(pos<=lastPos)
6241             return false;
6242           lastPos=pos;
6243           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6244         }
6245       else
6246         {
6247           if(sg.find(curType)==sg.end())
6248             {
6249               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6250               sg.insert(curType);
6251             }
6252           else
6253             return false;
6254         }
6255     }
6256   return true;
6257 }
6258
6259 /*!
6260  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6261  * 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
6262  * 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'.
6263  */
6264 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6265 {
6266   checkConnectivityFullyDefined();
6267   mcIdType nbOfCells=getNumberOfCells();
6268   const mcIdType *conn=_nodal_connec->begin();
6269   const mcIdType *connI=_nodal_connec_index->begin();
6270   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6271   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6272   tmpa->alloc(nbOfCells,1);
6273   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6274   tmpb->fillWithZero();
6275   mcIdType *tmp=tmpa->getPointer();
6276   mcIdType *tmp2=tmpb->getPointer();
6277   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6278     {
6279       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6280       if(where!=orderEnd)
6281         {
6282           mcIdType pos=ToIdType(std::distance(orderBg,where));
6283           tmp2[pos]++;
6284           tmp[std::distance(connI,i)]=pos;
6285         }
6286       else
6287         {
6288           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6289           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6290           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6291           throw INTERP_KERNEL::Exception(oss.str());
6292         }
6293     }
6294   nbPerType=tmpb.retn();
6295   return tmpa.retn();
6296 }
6297
6298 /*!
6299  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6300  *
6301  * \return a new object containing the old to new correspondence.
6302  *
6303  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6304  */
6305 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6306 {
6307   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6308 }
6309
6310 /*!
6311  * 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.
6312  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6313  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6314  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6315  */
6316 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6317 {
6318   DataArrayIdType *nbPerType=0;
6319   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6320   nbPerType->decrRef();
6321   return tmpa->buildPermArrPerLevel();
6322 }
6323
6324 /*!
6325  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6326  * The number of cells remains unchanged after the call of this method.
6327  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6328  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6329  *
6330  * \return the array giving the correspondence old to new.
6331  */
6332 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6333 {
6334   checkFullyDefined();
6335   computeTypes();
6336   const mcIdType *conn=_nodal_connec->begin();
6337   const mcIdType *connI=_nodal_connec_index->begin();
6338   mcIdType nbOfCells=getNumberOfCells();
6339   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6340   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6341     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6342       {
6343         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6344         types.push_back(curType);
6345         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6346       }
6347   DataArrayIdType *ret=DataArrayIdType::New();
6348   ret->alloc(nbOfCells,1);
6349   mcIdType *retPtr=ret->getPointer();
6350   std::fill(retPtr,retPtr+nbOfCells,-1);
6351   mcIdType newCellId=0;
6352   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6353     {
6354       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6355         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6356           retPtr[std::distance(connI,i)]=newCellId++;
6357     }
6358   renumberCells(retPtr,false);
6359   return ret;
6360 }
6361
6362 /*!
6363  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6364  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6365  * This method makes asumption that connectivity is correctly set before calling.
6366  */
6367 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6368 {
6369   checkConnectivityFullyDefined();
6370   const mcIdType *conn=_nodal_connec->begin();
6371   const mcIdType *connI=_nodal_connec_index->begin();
6372   mcIdType nbOfCells=getNumberOfCells();
6373   std::vector<MEDCouplingUMesh *> ret;
6374   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6375     {
6376       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6377       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6378       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6379       mcIdType endCellId=ToIdType(std::distance(connI,i));
6380       mcIdType sz=endCellId-beginCellId;
6381       mcIdType *cells=new mcIdType[sz];
6382       for(mcIdType j=0;j<sz;j++)
6383         cells[j]=beginCellId+j;
6384       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6385       delete [] cells;
6386       ret.push_back(m);
6387     }
6388   return ret;
6389 }
6390
6391 /*!
6392  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6393  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6394  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6395  *
6396  * \return a newly allocated instance, that the caller must manage.
6397  * \throw If \a this contains more than one geometric type.
6398  * \throw If the nodal connectivity of \a this is not fully defined.
6399  * \throw If the internal data is not coherent.
6400  */
6401 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6402 {
6403   checkConnectivityFullyDefined();
6404   if(_types.size()!=1)
6405     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6406   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6407   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6408   ret->setCoords(getCoords());
6409   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6410   if(retC)
6411     {
6412       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6413       retC->setNodalConnectivity(c);
6414     }
6415   else
6416     {
6417       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6418       if(!retD)
6419         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6420       DataArrayIdType *c=0,*ci=0;
6421       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6422       MCAuto<DataArrayIdType> cs(c),cis(ci);
6423       retD->setNodalConnectivity(cs,cis);
6424     }
6425   return ret.retn();
6426 }
6427
6428 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6429 {
6430   checkConnectivityFullyDefined();
6431   if(_types.size()!=1)
6432     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6433   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6434   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6435   if(cm.isDynamic())
6436     {
6437       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6438       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6439       throw INTERP_KERNEL::Exception(oss.str());
6440     }
6441   mcIdType nbCells=getNumberOfCells();
6442   mcIdType typi=ToIdType(typ);
6443   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6444   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6445   mcIdType *outPtr=connOut->getPointer();
6446   const mcIdType *conn=_nodal_connec->begin();
6447   const mcIdType *connI=_nodal_connec_index->begin();
6448   nbNodesPerCell++;
6449   for(mcIdType i=0;i<nbCells;i++,connI++)
6450     {
6451       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6452         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6453       else
6454         {
6455           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 << ") !";
6456           throw INTERP_KERNEL::Exception(oss.str());
6457         }
6458     }
6459   return connOut.retn();
6460 }
6461
6462 /*!
6463  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6464  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6465  * \param nodalConn nodal connectivity
6466  * \param nodalConnIndex nodal connectivity indices
6467  */
6468 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6469 {
6470   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6471   checkConnectivityFullyDefined();
6472   if(_types.size()!=1)
6473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6474   mcIdType nbCells=getNumberOfCells(),
6475            lgth=_nodal_connec->getNumberOfTuples();
6476   if(lgth<nbCells)
6477     throw INTERP_KERNEL::Exception(msg0);
6478   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6479   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6480   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6481   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6482   cip[0]=0;
6483   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6484     {
6485       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6486       mcIdType delta(stop-strt);
6487       if(delta>=1)
6488         {
6489           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6490             cp=std::copy(incp+strt,incp+stop,cp);
6491           else
6492             throw INTERP_KERNEL::Exception(msg0);
6493         }
6494       else
6495         throw INTERP_KERNEL::Exception(msg0);
6496       cip[1]=cip[0]+delta;
6497     }
6498   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6499 }
6500
6501 /*!
6502  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6503  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6504  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6505  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6506  * are not used here to avoid the build of big permutation array.
6507  *
6508  * \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
6509  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6510  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6511  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6512  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6513  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6514  * \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
6515  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6516  */
6517 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6518                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6519                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6520 {
6521   std::vector<const MEDCouplingUMesh *> ms2;
6522   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6523     if(*it)
6524       {
6525         (*it)->checkConnectivityFullyDefined();
6526         ms2.push_back(*it);
6527       }
6528   if(ms2.empty())
6529     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6530   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6531   int meshDim=ms2[0]->getMeshDimension();
6532   std::vector<const MEDCouplingUMesh *> m1ssm;
6533   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6534   //
6535   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6536   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6537   mcIdType fake=0,rk=0;
6538   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6539   ret1->alloc(0,1); ret2->alloc(0,1);
6540   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6541     {
6542       if(meshDim!=(*it)->getMeshDimension())
6543         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6544       if(refCoo!=(*it)->getCoords())
6545         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6546       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6547       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6548       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6549       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6550         {
6551           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6552           m1ssmSingleAuto.push_back(singleCell);
6553           m1ssmSingle.push_back(singleCell);
6554           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6555         }
6556     }
6557   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6558   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6559   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6560   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6561     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6562   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6563   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6564   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6565   return ret0.retn();
6566 }
6567
6568 /*!
6569  * This method returns a newly created DataArrayIdType instance.
6570  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6571  */
6572 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6573 {
6574   checkFullyDefined();
6575   const mcIdType *conn=_nodal_connec->begin();
6576   const mcIdType *connIndex=_nodal_connec_index->begin();
6577   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6578   for(const mcIdType *w=begin;w!=end;w++)
6579     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6580       ret->pushBackSilent(*w);
6581   return ret.retn();
6582 }
6583
6584 /*!
6585  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6586  * are in [0:getNumberOfCells())
6587  */
6588 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6589 {
6590   checkFullyDefined();
6591   const mcIdType *conn=_nodal_connec->begin();
6592   const mcIdType *connI=_nodal_connec_index->begin();
6593   mcIdType nbOfCells=getNumberOfCells();
6594   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6595   mcIdType *tmp=new mcIdType[nbOfCells];
6596   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6597     {
6598       mcIdType j=0;
6599       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6600         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6601           tmp[std::distance(connI,i)]=j++;
6602     }
6603   DataArrayIdType *ret=DataArrayIdType::New();
6604   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6605   ret->copyStringInfoFrom(*da);
6606   mcIdType *retPtr=ret->getPointer();
6607   const mcIdType *daPtr=da->begin();
6608   mcIdType nbOfElems=da->getNbOfElems();
6609   for(mcIdType k=0;k<nbOfElems;k++)
6610     retPtr[k]=tmp[daPtr[k]];
6611   delete [] tmp;
6612   return ret;
6613 }
6614
6615 /*!
6616  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6617  * This method \b works \b for mesh sorted by type.
6618  * cells whose ids is in 'idsPerGeoType' array.
6619  * This method conserves coords and name of mesh.
6620  */
6621 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6622 {
6623   std::vector<mcIdType> code=getDistributionOfTypes();
6624   std::size_t nOfTypesInThis=code.size()/3;
6625   mcIdType sz=0,szOfType=0;
6626   for(std::size_t i=0;i<nOfTypesInThis;i++)
6627     {
6628       if(code[3*i]!=type)
6629         sz+=code[3*i+1];
6630       else
6631         szOfType=code[3*i+1];
6632     }
6633   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6634     if(*work<0 || *work>=szOfType)
6635       {
6636         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6637         oss << ". It should be in [0," << szOfType << ") !";
6638         throw INTERP_KERNEL::Exception(oss.str());
6639       }
6640   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6641   mcIdType *idsPtr=idsTokeep->getPointer();
6642   mcIdType offset=0;
6643   for(std::size_t i=0;i<nOfTypesInThis;i++)
6644     {
6645       if(code[3*i]!=type)
6646         for(mcIdType j=0;j<code[3*i+1];j++)
6647           *idsPtr++=offset+j;
6648       else
6649         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6650       offset+=code[3*i+1];
6651     }
6652   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6653   ret->copyTinyInfoFrom(this);
6654   return ret.retn();
6655 }
6656
6657 /*!
6658  * This method returns a vector of size 'this->getNumberOfCells()'.
6659  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6660  */
6661 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6662 {
6663   mcIdType ncell=getNumberOfCells();
6664   std::vector<bool> ret(ncell);
6665   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6666   const mcIdType *c=getNodalConnectivity()->begin();
6667   for(mcIdType i=0;i<ncell;i++)
6668     {
6669       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6670       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6671       ret[i]=cm.isQuadratic();
6672     }
6673   return ret;
6674 }
6675
6676 /*!
6677  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6678  */
6679 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6680 {
6681   if(other->getType()!=UNSTRUCTURED)
6682     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6683   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6684   return MergeUMeshes(this,otherC);
6685 }
6686
6687 /*!
6688  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6689  * computed by averaging coordinates of cell nodes, so this method is not a right
6690  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6691  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6692  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6693  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6694  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6695  *          components. The caller is to delete this array using decrRef() as it is
6696  *          no more needed.
6697  *  \throw If the coordinates array is not set.
6698  *  \throw If the nodal connectivity of cells is not defined.
6699  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6700  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6701  */
6702 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6703 {
6704   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6705   int spaceDim=getSpaceDimension();
6706   mcIdType nbOfCells=getNumberOfCells();
6707   ret->alloc(nbOfCells,spaceDim);
6708   ret->copyStringInfoFrom(*getCoords());
6709   double *ptToFill=ret->getPointer();
6710   const mcIdType *nodal=_nodal_connec->begin();
6711   const mcIdType *nodalI=_nodal_connec_index->begin();
6712   const double *coor=_coords->begin();
6713   for(mcIdType i=0;i<nbOfCells;i++)
6714     {
6715       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6716       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6717       ptToFill+=spaceDim;
6718     }
6719   return ret.retn();
6720 }
6721
6722
6723 /*!
6724  * See computeCellCenterOfMass().
6725  *  \param eps a precision for the detection of degenerated arc of circles.
6726  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6727  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6728  *          components. The caller is to delete this array using decrRef() as it is
6729  *          no more needed.
6730  *  \throw If the coordinates array is not set.
6731  *  \throw If the nodal connectivity of cells is not defined.
6732  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6733  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6734  */
6735 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6736 {
6737   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6738   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6739   return ret.retn();
6740 }
6741
6742
6743 /*!
6744  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6745  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6746  *
6747  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6748  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6749  *
6750  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6751  * \throw If \a this is not fully defined (coordinates and connectivity)
6752  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6753  */
6754 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6755 {
6756   checkFullyDefined();
6757   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6758   int spaceDim=getSpaceDimension();
6759   mcIdType nbOfCells=getNumberOfCells();
6760   mcIdType nbOfNodes=getNumberOfNodes();
6761   ret->alloc(nbOfCells,spaceDim);
6762   double *ptToFill=ret->getPointer();
6763   const mcIdType *nodal=_nodal_connec->begin();
6764   const mcIdType *nodalI=_nodal_connec_index->begin();
6765   const double *coor=_coords->begin();
6766   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6767     {
6768       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6769       std::fill(ptToFill,ptToFill+spaceDim,0.);
6770       if(type!=INTERP_KERNEL::NORM_POLYHED)
6771         {
6772           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6773             {
6774               if(*conn>=0 && *conn<nbOfNodes)
6775                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6776               else
6777                 {
6778                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6779                   throw INTERP_KERNEL::Exception(oss.str());
6780                 }
6781             }
6782           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6783           if(nbOfNodesInCell>0)
6784             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6785           else
6786             {
6787               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6788               throw INTERP_KERNEL::Exception(oss.str());
6789             }
6790         }
6791       else
6792         {
6793           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6794           s.erase(-1);
6795           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6796             {
6797               if(*it>=0 && *it<nbOfNodes)
6798                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6799               else
6800                 {
6801                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6802                   throw INTERP_KERNEL::Exception(oss.str());
6803                 }
6804             }
6805           if(!s.empty())
6806             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6807           else
6808             {
6809               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6810               throw INTERP_KERNEL::Exception(oss.str());
6811             }
6812         }
6813     }
6814   return ret.retn();
6815 }
6816
6817 /*!
6818  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6819  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6820  * are specified via an array of cell ids.
6821  *  \warning Validity of the specified cell ids is not checked!
6822  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6823  *  \param [in] begin - an array of cell ids of interest.
6824  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6825  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6826  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6827  *          caller is to delete this array using decrRef() as it is no more needed.
6828  *  \throw If the coordinates array is not set.
6829  *  \throw If the nodal connectivity of cells is not defined.
6830  *
6831  *  \if ENABLE_EXAMPLES
6832  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6833  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6834  *  \endif
6835  */
6836 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6837 {
6838   DataArrayDouble *ret=DataArrayDouble::New();
6839   int spaceDim=getSpaceDimension();
6840   std::size_t nbOfTuple=std::distance(begin,end);
6841   ret->alloc(nbOfTuple,spaceDim);
6842   double *ptToFill=ret->getPointer();
6843   double *tmp=new double[spaceDim];
6844   const mcIdType *nodal=_nodal_connec->begin();
6845   const mcIdType *nodalI=_nodal_connec_index->begin();
6846   const double *coor=_coords->begin();
6847   for(const mcIdType *w=begin;w!=end;w++)
6848     {
6849       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6850       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6851       ptToFill+=spaceDim;
6852     }
6853   delete [] tmp;
6854   return ret;
6855 }
6856
6857 /*!
6858  * 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".
6859  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6860  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6861  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6862  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6863  *
6864  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6865  * \throw If spaceDim!=3 or meshDim!=2.
6866  * \throw If connectivity of \a this is invalid.
6867  * \throw If connectivity of a cell in \a this points to an invalid node.
6868  */
6869 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6870 {
6871   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6872   mcIdType nbOfCells=getNumberOfCells();
6873   mcIdType nbOfNodes(getNumberOfNodes());
6874   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6875     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6876   ret->alloc(nbOfCells,4);
6877   double *retPtr(ret->getPointer());
6878   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6879   const double *coor(_coords->begin());
6880   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6881     {
6882       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6883       if(nodalI[1]-nodalI[0]>=4)
6884         {
6885           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6886                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6887                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6888           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6889                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6890                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6891           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]};
6892           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]));
6893           for(int j=0;j<3;j++)
6894             {
6895               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6896               if(nodeId>=0 && nodeId<nbOfNodes)
6897                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6898               else
6899                 {
6900                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6901                   throw INTERP_KERNEL::Exception(oss.str());
6902                 }
6903             }
6904           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6905             {
6906               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6907               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6908             }
6909           else
6910             {
6911               if(nodalI[1]-nodalI[0]==4)
6912                 {
6913                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6914                   throw INTERP_KERNEL::Exception(oss.str());
6915                 }
6916               //
6917               double dd[3]={0.,0.,0.};
6918               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6919                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6920               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6921               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6922               std::copy(dd,dd+3,matrix+4*2);
6923               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6924               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6925             }
6926         }
6927       else
6928         {
6929           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6930           throw INTERP_KERNEL::Exception(oss.str());
6931         }
6932     }
6933   return ret.retn();
6934 }
6935
6936 /*!
6937  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6938  *
6939  */
6940 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6941 {
6942   if(!da)
6943     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6944   da->checkAllocated();
6945   std::string name(da->getName());
6946   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6947   if(name.empty())
6948     ret->setName("Mesh");
6949   ret->setCoords(da);
6950   mcIdType nbOfTuples(da->getNumberOfTuples());
6951   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6952   c->alloc(2*nbOfTuples,1);
6953   cI->alloc(nbOfTuples+1,1);
6954   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6955   *cip++=0;
6956   for(mcIdType i=0;i<nbOfTuples;i++)
6957     {
6958       *cp++=INTERP_KERNEL::NORM_POINT1;
6959       *cp++=i;
6960       *cip++=2*(i+1);
6961     }
6962   ret->setConnectivity(c,cI,true);
6963   return ret.retn();
6964 }
6965
6966 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6967 {
6968   if(!da)
6969     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6970   da->checkAllocated();
6971   std::string name(da->getName());
6972   MCAuto<MEDCouplingUMesh> ret;
6973   {
6974     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6975     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6976     arr->alloc(da->getNumberOfTuples());
6977     tmp->setCoordsAt(0,arr);
6978     ret=tmp->buildUnstructured();
6979   }
6980   ret->setCoords(da);
6981   if(name.empty())
6982     ret->setName("Mesh");
6983   else
6984     ret->setName(name);
6985   return ret;
6986 }
6987
6988 /*!
6989  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6990  * Cells and nodes of
6991  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6992  *  \param [in] mesh1 - the first mesh.
6993  *  \param [in] mesh2 - the second mesh.
6994  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6995  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6996  *          is no more needed.
6997  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6998  *  \throw If the coordinates array is not set in none of the meshes.
6999  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7000  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7001  */
7002 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7003 {
7004   std::vector<const MEDCouplingUMesh *> tmp(2);
7005   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7006   return MergeUMeshes(tmp);
7007 }
7008
7009 /*!
7010  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7011  * Cells and nodes of
7012  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7013  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7014  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7015  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7016  *          is no more needed.
7017  *  \throw If \a a.size() == 0.
7018  *  \throw If \a a[ *i* ] == NULL.
7019  *  \throw If the coordinates array is not set in none of the meshes.
7020  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7021  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7022  */
7023 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7024 {
7025   std::size_t sz=a.size();
7026   if(sz==0)
7027     return MergeUMeshesLL(a);
7028   for(std::size_t ii=0;ii<sz;ii++)
7029     if(!a[ii])
7030       {
7031         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7032         throw INTERP_KERNEL::Exception(oss.str());
7033       }
7034   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7035   std::vector< const MEDCouplingUMesh * > aa(sz);
7036   int spaceDim=-3;
7037   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7038     {
7039       const MEDCouplingUMesh *cur=a[i];
7040       const DataArrayDouble *coo=cur->getCoords();
7041       if(coo)
7042         spaceDim=int(coo->getNumberOfComponents());
7043     }
7044   if(spaceDim==-3)
7045     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7046   for(std::size_t i=0;i<sz;i++)
7047     {
7048       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7049       aa[i]=bb[i];
7050     }
7051   return MergeUMeshesLL(aa);
7052 }
7053
7054 /*!
7055  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7056  * dimension and sharing the node coordinates array.
7057  * All cells of the first mesh precede all cells of the second mesh
7058  * within the result mesh.
7059  *  \param [in] mesh1 - the first mesh.
7060  *  \param [in] mesh2 - the second mesh.
7061  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7062  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7063  *          is no more needed.
7064  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7065  *  \throw If the meshes do not share the node coordinates array.
7066  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7067  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7068  */
7069 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7070 {
7071   std::vector<const MEDCouplingUMesh *> tmp(2);
7072   tmp[0]=mesh1; tmp[1]=mesh2;
7073   return MergeUMeshesOnSameCoords(tmp);
7074 }
7075
7076 /*!
7077  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7078  * dimension and sharing the node coordinates array.
7079  * All cells of the *i*-th mesh precede all cells of the
7080  * (*i*+1)-th mesh within the result mesh.
7081  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7082  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7083  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7084  *          is no more needed.
7085  *  \throw If \a a.size() == 0.
7086  *  \throw If \a a[ *i* ] == NULL.
7087  *  \throw If the meshes do not share the node coordinates array.
7088  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7089  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7090  */
7091 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7092 {
7093   if(meshes.empty())
7094     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7095   for(std::size_t ii=0;ii<meshes.size();ii++)
7096     if(!meshes[ii])
7097       {
7098         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7099         throw INTERP_KERNEL::Exception(oss.str());
7100       }
7101   const DataArrayDouble *coords=meshes.front()->getCoords();
7102   int meshDim=meshes.front()->getMeshDimension();
7103   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7104   mcIdType meshLgth=0;
7105   mcIdType meshIndexLgth=0;
7106   for(;iter!=meshes.end();iter++)
7107     {
7108       if(coords!=(*iter)->getCoords())
7109         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7110       if(meshDim!=(*iter)->getMeshDimension())
7111         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7112       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7113       meshIndexLgth+=(*iter)->getNumberOfCells();
7114     }
7115   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7116   nodal->alloc(meshLgth,1);
7117   mcIdType *nodalPtr=nodal->getPointer();
7118   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7119   nodalIndex->alloc(meshIndexLgth+1,1);
7120   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7121   mcIdType offset=0;
7122   for(iter=meshes.begin();iter!=meshes.end();iter++)
7123     {
7124       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7125       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7126       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7127       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7128       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7129       if(iter!=meshes.begin())
7130         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7131       else
7132         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7133       offset+=meshLgth2;
7134     }
7135   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7136   ret->setName("merge");
7137   ret->setMeshDimension(meshDim);
7138   ret->setConnectivity(nodal,nodalIndex,true);
7139   ret->setCoords(coords);
7140   return ret;
7141 }
7142
7143 /*!
7144  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7145  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7146  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7147  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7148  * New" mode are returned for each input mesh.
7149  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7150  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7151  *          valid values [0,1,2], see zipConnectivityTraducer().
7152  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7153  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7154  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7155  *          no more needed.
7156  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7157  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7158  *          is no more needed.
7159  *  \throw If \a meshes.size() == 0.
7160  *  \throw If \a meshes[ *i* ] == NULL.
7161  *  \throw If the meshes do not share the node coordinates array.
7162  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7163  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7164  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7165  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7166  */
7167 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7168 {
7169   //All checks are delegated to MergeUMeshesOnSameCoords
7170   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7171   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7172   corr.resize(meshes.size());
7173   std::size_t nbOfMeshes=meshes.size();
7174   mcIdType offset=0;
7175   const mcIdType *o2nPtr=o2n->begin();
7176   for(std::size_t i=0;i<nbOfMeshes;i++)
7177     {
7178       DataArrayIdType *tmp=DataArrayIdType::New();
7179       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7180       tmp->alloc(curNbOfCells,1);
7181       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7182       offset+=curNbOfCells;
7183       tmp->setName(meshes[i]->getName());
7184       corr[i]=tmp;
7185     }
7186   return ret.retn();
7187 }
7188
7189 /*!
7190  * Makes all given meshes share the nodal connectivity array. The common connectivity
7191  * array is created by concatenating the connectivity arrays of all given meshes. All
7192  * the given meshes must be of the same space dimension but dimension of cells **can
7193  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7194  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7195  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7196  *  \param [in,out] meshes - a vector of meshes to update.
7197  *  \throw If any of \a meshes is NULL.
7198  *  \throw If the coordinates array is not set in any of \a meshes.
7199  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7200  *  \throw If \a meshes are of different space dimension.
7201  */
7202 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7203 {
7204   std::size_t sz=meshes.size();
7205   if(sz==0 || sz==1)
7206     return;
7207   std::vector< const DataArrayDouble * > coords(meshes.size());
7208   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7209   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7210     {
7211       if((*it))
7212         {
7213           (*it)->checkConnectivityFullyDefined();
7214           const DataArrayDouble *coo=(*it)->getCoords();
7215           if(coo)
7216             *it2=coo;
7217           else
7218             {
7219               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7220               oss << " has no coordinate array defined !";
7221               throw INTERP_KERNEL::Exception(oss.str());
7222             }
7223         }
7224       else
7225         {
7226           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7227           oss << " is null !";
7228           throw INTERP_KERNEL::Exception(oss.str());
7229         }
7230     }
7231   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7232   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7233   mcIdType offset=(*it)->getNumberOfNodes();
7234   (*it++)->setCoords(res);
7235   for(;it!=meshes.end();it++)
7236     {
7237       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7238       (*it)->setCoords(res);
7239       (*it)->shiftNodeNumbersInConn(offset);
7240       offset+=oldNumberOfNodes;
7241     }
7242 }
7243
7244 /*!
7245  * Merges nodes coincident with a given precision within all given meshes that share
7246  * the nodal connectivity array. The given meshes **can be of different** mesh
7247  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7248  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7249  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7250  *  \param [in,out] meshes - a vector of meshes to update.
7251  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7252  *  \throw If any of \a meshes is NULL.
7253  *  \throw If the \a meshes do not share the same node coordinates array.
7254  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7255  */
7256 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7257 {
7258   if(meshes.empty())
7259     return ;
7260   std::set<const DataArrayDouble *> s;
7261   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7262     {
7263       if(*it)
7264         s.insert((*it)->getCoords());
7265       else
7266         {
7267           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 !";
7268           throw INTERP_KERNEL::Exception(oss.str());
7269         }
7270     }
7271   if(s.size()!=1)
7272     {
7273       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 !";
7274       throw INTERP_KERNEL::Exception(oss.str());
7275     }
7276   const DataArrayDouble *coo=*(s.begin());
7277   if(!coo)
7278     return;
7279   //
7280   DataArrayIdType *comm,*commI;
7281   coo->findCommonTuples(eps,-1,comm,commI);
7282   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7283   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7284   mcIdType newNbOfNodes;
7285   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7286   if(oldNbOfNodes==newNbOfNodes)
7287     return ;
7288   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7289   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7290     {
7291       (*it)->renumberNodesInConn(o2n->begin());
7292       (*it)->setCoords(newCoords);
7293     }
7294 }
7295
7296
7297 /*!
7298  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7299  */
7300 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7301 {
7302   std::size_t i, ip1;
7303   double v[3]={0.,0.,0.};
7304   std::size_t sz=std::distance(begin,end);
7305   if(!isQuadratic)
7306     for(i=0;i<sz;i++)
7307       {
7308         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7309         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7310         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];
7311         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7312         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7313       }
7314   else
7315     {
7316       // Same algorithm as above but also using intermediate quadratic points.
7317       // (taking only linear points might lead to issues if the linearized version of the
7318       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7319       std::size_t hsz = sz/2;
7320       for(std::size_t j=0;j<sz;j++)
7321         {
7322           if (j%2)  // current point i is quadratic, next point i+1 is standard
7323             {
7324               i = hsz+(j-1)/2;
7325               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7326             }
7327           else      // current point i is standard, next point i+1 is quadratic
7328             {
7329               i = j/2;
7330               ip1 = j/2+hsz;
7331             }
7332           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7333           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7334           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7335         }
7336     }
7337   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7338   return (ret>0.);
7339 }
7340
7341 /*!
7342  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7343  */
7344 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7345 {
7346   std::vector<std::pair<mcIdType,mcIdType> > edges;
7347   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7348   const mcIdType *bgFace=begin;
7349   for(std::size_t i=0;i<nbOfFaces;i++)
7350     {
7351       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7352       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7353       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7354         {
7355           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7356           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7357             return false;
7358           edges.push_back(p1);
7359         }
7360       bgFace=endFace+1;
7361     }
7362   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7363 }
7364
7365 /*!
7366  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7367  */
7368 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7369 {
7370   double vec0[3],vec1[3];
7371   std::size_t sz=std::distance(begin,end);
7372   if(sz%2!=0)
7373     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7374   mcIdType nbOfNodes=ToIdType(sz/2);
7375   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7376   const double *pt0=coords+3*begin[0];
7377   const double *pt1=coords+3*begin[nbOfNodes];
7378   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7379   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7380 }
7381
7382 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7383 {
7384   std::size_t sz=std::distance(begin,end);
7385   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7386   std::size_t nbOfNodes(sz/2);
7387   std::copy(begin,end,(mcIdType *)tmp);
7388   for(std::size_t j=1;j<nbOfNodes;j++)
7389     {
7390       begin[j]=tmp[nbOfNodes-j];
7391       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7392     }
7393 }
7394
7395 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7396 {
7397   std::size_t sz=std::distance(begin,end);
7398   if(sz!=4)
7399     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7400   double vec0[3],vec1[3];
7401   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7402   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];
7403   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;
7404 }
7405
7406 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7407 {
7408   std::size_t sz=std::distance(begin,end);
7409   if(sz!=5)
7410     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7411   double vec0[3];
7412   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7413   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7414   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7415 }
7416
7417 /*!
7418  * 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 )
7419  * 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
7420  * a 2D space.
7421  *
7422  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7423  * \param [in] coords the coordinates with nb of components exactly equal to 3
7424  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7425  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7426  */
7427 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7428                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7429 {
7430   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7431   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7432   double *vPtr=v->getPointer();
7433   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7434   double *pPtr=p->getPointer();
7435   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7436   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7437   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7438     {
7439       mcIdType face = e_f[e_fi[index] + i];
7440       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7441       // to differentiate faces going to different cells:
7442       pPtr++, *pPtr = 0;
7443       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7444         *pPtr += FromIdType<double>(f_e[j]);
7445     }
7446   pPtr=p->getPointer(); vPtr=v->getPointer();
7447   DataArrayIdType *comm1=0,*commI1=0;
7448   v->findCommonTuples(eps,-1,comm1,commI1);
7449   for (mcIdType i = 0; i < nbFaces; i++)
7450     if (comm1->findIdFirstEqual(i) < 0)
7451       {
7452         comm1->pushBackSilent(i);
7453         commI1->pushBackSilent(comm1->getNumberOfTuples());
7454       }
7455   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7456   const mcIdType *comm1Ptr=comm1->begin();
7457   const mcIdType *commI1Ptr=commI1->begin();
7458   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7459   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7460   //
7461   for(mcIdType i=0;i<nbOfGrps1;i++)
7462     {
7463       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7464       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7465       DataArrayIdType *comm2=0,*commI2=0;
7466       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7467       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7468         if (comm2->findIdFirstEqual(j) < 0)
7469           {
7470             comm2->pushBackSilent(j);
7471             commI2->pushBackSilent(comm2->getNumberOfTuples());
7472           }
7473       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7474       const mcIdType *comm2Ptr=comm2->begin();
7475       const mcIdType *commI2Ptr=commI2->begin();
7476       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7477       for(mcIdType j=0;j<nbOfGrps2;j++)
7478         {
7479           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7480             {
7481               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7482               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7483               res->pushBackSilent(-1);
7484             }
7485           else
7486             {
7487               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7488               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7489               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7490               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7491               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7492               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7493               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7494               const mcIdType *idsNodePtr=idsNode->begin();
7495               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];
7496               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7497               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7498               if(std::abs(norm)>eps)
7499                 {
7500                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7501                   mm3->rotate(center,vec,angle);
7502                 }
7503               mm3->changeSpaceDimension(2);
7504               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7505               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7506               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7507               mcIdType nbOfCells=mm4->getNumberOfCells();
7508               for(mcIdType k=0;k<nbOfCells;k++)
7509                 {
7510                   int l=0;
7511                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7512                     res->pushBackSilent(idsNodePtr[*work]);
7513                   res->pushBackSilent(-1);
7514                 }
7515             }
7516         }
7517     }
7518   res->popBackSilent();
7519 }
7520
7521 /*!
7522  * 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
7523  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7524  *
7525  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7526  * \param [in] coords coordinates expected to have 3 components.
7527  * \param [in] begin start of the nodal connectivity of the face.
7528  * \param [in] end end of the nodal connectivity (excluded) of the face.
7529  * \param [out] v the normalized vector of size 3
7530  * \param [out] p the pos of plane
7531  */
7532 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7533 {
7534   std::size_t nbPoints=std::distance(begin,end);
7535   if(nbPoints<3)
7536     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7537   double vec[3]={0.,0.,0.};
7538   std::size_t j=0;
7539   bool refFound=false;
7540   for(;j<nbPoints-1 && !refFound;j++)
7541     {
7542       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7543       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7544       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7545       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7546       if(norm>eps)
7547         {
7548           refFound=true;
7549           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7550         }
7551     }
7552   for(std::size_t i=j;i<nbPoints-1;i++)
7553     {
7554       double curVec[3];
7555       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7556       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7557       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7558       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7559       if(norm<eps)
7560         continue;
7561       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7562       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];
7563       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7564       if(norm>eps)
7565         {
7566           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7567           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7568           return ;
7569         }
7570     }
7571   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7572 }
7573
7574 /*!
7575  * This method tries to obtain a well oriented polyhedron.
7576  * If the algorithm fails, an exception will be thrown.
7577  */
7578 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7579 {
7580   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7581   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7582   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7583   isPerm[0]=true;
7584   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7585   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7586   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7587   //
7588   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7589     {
7590       bgFace=begin;
7591       std::size_t smthChanged=0;
7592       for(std::size_t i=0;i<nbOfFaces;i++)
7593         {
7594           endFace=std::find(bgFace+1,end,-1);
7595           nbOfEdgesInFace=std::distance(bgFace,endFace);
7596           if(!isPerm[i])
7597             {
7598               bool b=false;
7599               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7600                 {
7601                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7602                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7603                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7604                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7605                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7606                 }
7607               if(isPerm[i])
7608                 {
7609                   if(!b)
7610                     std::reverse(bgFace+1,endFace);
7611                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7612                     {
7613                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7614                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7615                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7616                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7617                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7618                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7619                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7620                       if(it!=edgesOK.end())
7621                         {
7622                           edgesOK.erase(it);
7623                           edgesFinished.push_back(p1);
7624                         }
7625                       else
7626                         edgesOK.push_back(p1);
7627                     }
7628                 }
7629             }
7630           bgFace=endFace+1;
7631         }
7632       if(smthChanged==0)
7633         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7634     }
7635   if(!edgesOK.empty())
7636     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7637   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7638     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7639       bgFace=begin;
7640       for(std::size_t i=0;i<nbOfFaces;i++)
7641         {
7642           endFace=std::find(bgFace+1,end,-1);
7643           std::reverse(bgFace+1,endFace);
7644           bgFace=endFace+1;
7645         }
7646     }
7647 }
7648
7649
7650 /*!
7651  * This method makes the assumption spacedimension == meshdimension == 2.
7652  * This method works only for linear cells.
7653  *
7654  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7655  */
7656 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7657 {
7658   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7659     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7660   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7661   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7662   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7663   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7664   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7665   mcIdType nbCells=skin->getNumberOfCells();
7666   if(nbCells==nbOfNodesExpected)
7667     return buildUnionOf2DMeshLinear(skin,n2o);
7668   else if(2*nbCells==nbOfNodesExpected)
7669     return buildUnionOf2DMeshQuadratic(skin,n2o);
7670   else
7671     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7672 }
7673
7674 /*!
7675  * This method makes the assumption spacedimension == meshdimension == 3.
7676  * This method works only for linear cells.
7677  *
7678  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7679  */
7680 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7681 {
7682   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7683     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7684   MCAuto<MEDCouplingUMesh> m=computeSkin();
7685   const mcIdType *conn=m->getNodalConnectivity()->begin();
7686   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7687   mcIdType nbOfCells=m->getNumberOfCells();
7688   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7689   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7690   if(nbOfCells<1)
7691     return ret.retn();
7692   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7693   for(mcIdType i=1;i<nbOfCells;i++)
7694     {
7695       *work++=-1;
7696       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7697     }
7698   return ret.retn();
7699 }
7700
7701 /*!
7702  * \brief Creates a graph of cell neighbors
7703  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7704  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7705  *  For example
7706  *  - index:  0 3 5 6 6
7707  *  - value:  1 2 3 2 3 3
7708  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7709  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7710  */
7711 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7712 {
7713   checkConnectivityFullyDefined();
7714
7715   int meshDim = this->getMeshDimension();
7716   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7717   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7718   this->getReverseNodalConnectivity(revConn,indexr);
7719   const mcIdType* indexr_ptr=indexr->begin();
7720   const mcIdType* revConn_ptr=revConn->begin();
7721
7722   const MEDCoupling::DataArrayIdType* index;
7723   const MEDCoupling::DataArrayIdType* conn;
7724   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7725   index=this->getNodalConnectivityIndex();
7726   mcIdType nbCells=this->getNumberOfCells();
7727   const mcIdType* index_ptr=index->begin();
7728   const mcIdType* conn_ptr=conn->begin();
7729
7730   //creating graph arcs (cell to cell relations)
7731   //arcs are stored in terms of (index,value) notation
7732   // 0 3 5 6 6
7733   // 1 2 3 2 3 3
7734   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7735   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7736
7737   //warning here one node have less than or equal effective number of cell with it
7738   //but cell could have more than effective nodes
7739   //because other equals nodes in other domain (with other global inode)
7740   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7741   std::vector <mcIdType> cell2cell;
7742   cell2cell.reserve(3*nbCells);
7743
7744   for (mcIdType icell=0; icell<nbCells;icell++)
7745     {
7746       std::map<mcIdType,mcIdType > counter;
7747       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7748         {
7749           mcIdType inode=conn_ptr[iconn];
7750           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7751             {
7752               mcIdType icell2=revConn_ptr[iconnr];
7753               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7754               if (iter!=counter.end()) (iter->second)++;
7755               else counter.insert(std::make_pair(icell2,1));
7756             }
7757         }
7758       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7759            iter!=counter.end(); iter++)
7760         if (iter->second >= meshDim)
7761           {
7762             cell2cell_index[icell+1]++;
7763             cell2cell.push_back(iter->first);
7764           }
7765     }
7766   indexr->decrRef();
7767   revConn->decrRef();
7768   cell2cell_index[0]=0;
7769   for (mcIdType icell=0; icell<nbCells;icell++)
7770     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7771
7772   //filling up index and value to create skylinearray structure
7773   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7774   return array;
7775 }
7776
7777
7778 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7779 {
7780   mcIdType nbOfCells=getNumberOfCells();
7781   if(nbOfCells<=0)
7782     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7783   ofs << "  <" << getVTKDataSetType() << ">\n";
7784   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7785   ofs << "      <PointData>\n" << pointData << std::endl;
7786   ofs << "      </PointData>\n";
7787   ofs << "      <CellData>\n" << cellData << std::endl;
7788   ofs << "      </CellData>\n";
7789   ofs << "      <Points>\n";
7790   if(getSpaceDimension()==3)
7791     _coords->writeVTK(ofs,8,"Points",byteData);
7792   else
7793     {
7794       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7795       coo->writeVTK(ofs,8,"Points",byteData);
7796     }
7797   ofs << "      </Points>\n";
7798   ofs << "      <Cells>\n";
7799   const mcIdType *cPtr=_nodal_connec->begin();
7800   const mcIdType *cIPtr=_nodal_connec_index->begin();
7801   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7802   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7803   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7804   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7805   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7806   mcIdType szFaceOffsets=0,szConn=0;
7807   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7808     {
7809       *w2=cPtr[cIPtr[i]];
7810       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7811         {
7812           *w1=-1;
7813           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7814           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7815         }
7816       else
7817         {
7818           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7819           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7820           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7821           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7822           w4=std::copy(c.begin(),c.end(),w4);
7823         }
7824     }
7825   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7826   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7827     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7828   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7829   types->writeVTK(ofs,8,"UInt8","types",byteData);
7830   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7831   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7832   if(szFaceOffsets!=0)
7833     {//presence of Polyhedra
7834       connectivity->reAlloc(szConn);
7835       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7836       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7837       w1=faces->getPointer();
7838       for(mcIdType i=0;i<nbOfCells;i++)
7839         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7840           {
7841             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7842             *w1++=nbFaces;
7843             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7844             for(mcIdType j=0;j<nbFaces;j++)
7845               {
7846                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7847                 *w1++=ToIdType(std::distance(w6,w5));
7848                 w1=std::copy(w6,w5,w1);
7849                 w6=w5+1;
7850               }
7851           }
7852       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7853     }
7854   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7855   ofs << "      </Cells>\n";
7856   ofs << "    </Piece>\n";
7857   ofs << "  </" << getVTKDataSetType() << ">\n";
7858 }
7859
7860 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7861 {
7862   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7863   if(_mesh_dim==-2)
7864     { stream << " Not set !"; return ; }
7865   stream << " Mesh dimension : " << _mesh_dim << ".";
7866   if(_mesh_dim==-1)
7867     return ;
7868   if(!_coords)
7869     { stream << " No coordinates set !"; return ; }
7870   if(!_coords->isAllocated())
7871     { stream << " Coordinates set but not allocated !"; return ; }
7872   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7873   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7874   if(!_nodal_connec_index)
7875     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7876   if(!_nodal_connec_index->isAllocated())
7877     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7878   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7879   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7880   if(cpt!=1 || lgth<1)
7881     return ;
7882   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7883 }
7884
7885 std::string MEDCouplingUMesh::getVTKDataSetType() const
7886 {
7887   return std::string("UnstructuredGrid");
7888 }
7889
7890 std::string MEDCouplingUMesh::getVTKFileExtension() const
7891 {
7892   return std::string("vtu");
7893 }
7894
7895
7896
7897 /**
7898  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7899  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7900  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7901  * The caller is to deal with the resulting DataArrayIdType.
7902  *  \throw If the coordinate array is not set.
7903  *  \throw If the nodal connectivity of the cells is not defined.
7904  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7905  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7906  *
7907  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7908  */
7909 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7910 {
7911   checkFullyDefined();
7912   if(getMeshDimension()!=1)
7913     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7914
7915   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7916   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7917   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7918   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7919   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7920   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7921   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7922   const mcIdType * dsi(_dsi->begin());
7923   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7924   m_points=0;
7925   if (dsii->getNumberOfTuples())
7926     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7927
7928   mcIdType nc=getNumberOfCells();
7929   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7930   result->alloc(nc,1);
7931
7932   // set of edges not used so far
7933   std::set<mcIdType> edgeSet;
7934   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7935
7936   mcIdType startSeg=0;
7937   mcIdType newIdx=0;
7938   // while we have points with only one neighbor segments
7939   do
7940     {
7941       std::list<mcIdType> linePiece;
7942       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7943       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7944         {
7945           // Fill the list forward (resp. backward) from the start segment:
7946           mcIdType activeSeg = startSeg;
7947           mcIdType prevPointId = -20;
7948           mcIdType ptId;
7949           while (!edgeSet.empty())
7950             {
7951               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7952                 {
7953                   if (direction==0)
7954                     linePiece.push_back(activeSeg);
7955                   else
7956                     linePiece.push_front(activeSeg);
7957                   edgeSet.erase(activeSeg);
7958                 }
7959
7960               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7961               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7962               if (dsi[ptId] == 1) // hitting the end of the line
7963                 break;
7964
7965               prevPointId = ptId;
7966               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7967               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7968
7969               //for piecewise meshes made up of closed parts
7970               bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7971               if(segmentAlreadyTreated)
7972                 break;
7973             }
7974         }
7975       // Done, save final piece into DA:
7976       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7977       newIdx += ToIdType(linePiece.size());
7978
7979       // identify next valid start segment (one which is not consumed)
7980       if(!edgeSet.empty())
7981         startSeg = *(edgeSet.begin());
7982
7983     }
7984   while (!edgeSet.empty());
7985   return result.retn();
7986 }
7987
7988 /**
7989  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7990  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7991  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7992  * a minimal creation of new nodes is wanted.
7993  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7994  * nodes if a SEG3 is split without information of middle.
7995  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7996  * avoid to have a non conform mesh.
7997  *
7998  * \return mcIdType - the number of new nodes created (in most of cases 0).
7999  *
8000  * \throw If \a this is not coherent.
8001  * \throw If \a this has not spaceDim equal to 2.
8002  * \throw If \a this has not meshDim equal to 2.
8003  * \throw If some subcells needed to be split are orphan.
8004  * \sa MEDCouplingUMesh::conformize2D
8005  */
8006 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8007 {
8008   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8009     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8010   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8011   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8012     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8013   if(midOpt==0 && midOptI==0)
8014     {
8015       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8016       return 0;
8017     }
8018   else if(midOpt!=0 && midOptI!=0)
8019     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8020   else
8021     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8022 }
8023
8024 /*!
8025  * 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
8026  * 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
8027  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8028  * 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
8029  * 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.
8030  *
8031  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8032  */
8033 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8034 {
8035   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8036   if(sz>=4)
8037     {
8038       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8039       if(cm.getDimension()==2)
8040         {
8041           const mcIdType *node=nodalConnBg+1;
8042           mcIdType startNode=*node++;
8043           double refX=coords[2*startNode];
8044           for(;node!=nodalConnEnd;node++)
8045             {
8046               if(coords[2*(*node)]<refX)
8047                 {
8048                   startNode=*node;
8049                   refX=coords[2*startNode];
8050                 }
8051             }
8052           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8053           refX=1e300;
8054           double tmp1;
8055           double tmp2[2];
8056           double angle0=-M_PI/2;
8057           //
8058           mcIdType nextNode=-1;
8059           mcIdType prevNode=-1;
8060           double resRef;
8061           double angleNext=0.;
8062           while(nextNode!=startNode)
8063             {
8064               nextNode=-1;
8065               resRef=1e300;
8066               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8067                 {
8068                   if(*node!=tmpOut.back() && *node!=prevNode)
8069                     {
8070                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8071                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8072                       double res;
8073                       if(angleM<=angle0)
8074                         res=angle0-angleM;
8075                       else
8076                         res=angle0-angleM+2.*M_PI;
8077                       if(res<resRef)
8078                         {
8079                           nextNode=*node;
8080                           resRef=res;
8081                           angleNext=angleM;
8082                         }
8083                     }
8084                 }
8085               if(nextNode!=startNode)
8086                 {
8087                   angle0=angleNext-M_PI;
8088                   if(angle0<-M_PI)
8089                     angle0+=2*M_PI;
8090                   prevNode=tmpOut.back();
8091                   tmpOut.push_back(nextNode);
8092                 }
8093             }
8094           std::vector<mcIdType> tmp3(2*(sz-1));
8095           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8096           std::copy(nodalConnBg+1,nodalConnEnd,it);
8097           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8098             {
8099               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8100               return false;
8101             }
8102           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8103             {
8104               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8105               return false;
8106             }
8107           else
8108             {
8109               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8110               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8111               return true;
8112             }
8113         }
8114       else
8115         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8116     }
8117   else
8118     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8119 }
8120
8121 /*!
8122  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8123  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8124  * 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]].
8125  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8126  * A negative value in \b arrIn means that it is ignored.
8127  * 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.
8128  *
8129  * \param [in] arrIn arr origin array from which the extraction will be done.
8130  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8131  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8132  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8133  */
8134 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8135 {
8136   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8137   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8138 }
8139
8140 /*!
8141  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8142  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8143  * 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]].
8144  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8145  * A negative value in \b arrIn means that it is ignored.
8146  * 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.
8147  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8148  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8149  * \param [in] arrIn arr origin array from which the extraction will be done.
8150  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8151  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8152  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8153  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8154  * \sa MEDCouplingUMesh::partitionBySpreadZone
8155  */
8156 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8157 {
8158   nbOfDepthPeelingPerformed=0;
8159   if(!arrIndxIn)
8160     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8161   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8162   if(nbOfTuples<=0)
8163     {
8164       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8165       return ret;
8166     }
8167   //
8168   std::vector<bool> fetched(nbOfTuples,false);
8169   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8170 }
8171
8172
8173
8174 /*!
8175  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8176  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8177  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8178  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8179  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8180  *
8181  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8182  */
8183 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8184 {
8185   checkFullyDefined();
8186   int mdim=getMeshDimension();
8187   int spaceDim=getSpaceDimension();
8188   if(mdim!=spaceDim)
8189     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8190   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8191   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8192   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8193   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8194   ret->setCoords(getCoords());
8195   ret->allocateCells(ToIdType(partition.size()));
8196   //
8197   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8198     {
8199       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8200       MCAuto<DataArrayIdType> cell;
8201       switch(mdim)
8202       {
8203         case 2:
8204           cell=tmp->buildUnionOf2DMesh();
8205           break;
8206         case 3:
8207           cell=tmp->buildUnionOf3DMesh();
8208           break;
8209         default:
8210           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8211       }
8212
8213       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8214     }
8215   //
8216   ret->finishInsertingCells();
8217   return ret.retn();
8218 }
8219
8220 /*!
8221  * This method partitions \b this into contiguous zone.
8222  * This method only needs a well defined connectivity. Coordinates are not considered here.
8223  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8224  */
8225 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8226 {
8227   DataArrayIdType *neigh=0,*neighI=0;
8228   computeNeighborsOfCells(neigh,neighI);
8229   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8230   return PartitionBySpreadZone(neighAuto,neighIAuto);
8231 }
8232
8233 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8234 {
8235   if(!arrIn || !arrIndxIn)
8236     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8237   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8238   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8239   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8240     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8241   mcIdType nbOfCellsCur(nbOfTuples-1);
8242   std::vector<DataArrayIdType *> ret;
8243   if(nbOfCellsCur<=0)
8244     return ret;
8245   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8246   std::vector< MCAuto<DataArrayIdType> > ret2;
8247   mcIdType seed=0;
8248   while(seed<nbOfCellsCur)
8249     {
8250       mcIdType nbOfPeelPerformed=0;
8251       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8252       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8253     }
8254   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8255     ret.push_back((*it).retn());
8256   return ret;
8257 }
8258
8259 /*!
8260  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8261  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8262  *
8263  * \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.
8264  * \return a newly allocated DataArrayIdType to be managed by the caller.
8265  * \throw In case of \a code has not the right format (typically of size 3*n)
8266  */
8267 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8268 {
8269   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8270   std::size_t nb=code.size()/3;
8271   if(code.size()%3!=0)
8272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8273   ret->alloc(nb,2);
8274   mcIdType *retPtr=ret->getPointer();
8275   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8276     {
8277       retPtr[0]=code[3*i+2];
8278       retPtr[1]=code[3*i+2]+code[3*i+1];
8279     }
8280   return ret.retn();
8281 }
8282
8283 /*!
8284  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8285  * All cells in \a this are expected to be linear 3D cells.
8286  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8287  * It leads to an increase to number of cells.
8288  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8289  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8290  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8291  *
8292  * \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.
8293  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8294  * \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.
8295  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8296  *          an id of old cell producing it. The caller is to delete this array using
8297  *         decrRef() as it is no more needed.
8298  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8299  *
8300  * \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
8301  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8302  *
8303  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8304  * \throw If \a this is not fully constituted with linear 3D cells.
8305  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8306  */
8307 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8308 {
8309   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8310   checkConnectivityFullyDefined();
8311   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8312     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8313   mcIdType nbOfCells=getNumberOfCells();
8314   mcIdType nbNodes(getNumberOfNodes());
8315   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8316   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8317   mcIdType *retPt(ret->getPointer());
8318   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8319   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8320   const mcIdType *oldc(_nodal_connec->begin());
8321   const mcIdType *oldci(_nodal_connec_index->begin());
8322   const double *coords(_coords->begin());
8323   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8324     {
8325       std::vector<mcIdType> a; std::vector<double> b;
8326       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8327       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8328       const mcIdType *aa(&a[0]);
8329       if(!b.empty())
8330         {
8331           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8332             if(*it<0)
8333               *it=(-(*(it))-1+nbNodes);
8334           addPts->insertAtTheEnd(b.begin(),b.end());
8335           nbNodes+=ToIdType(b.size()/3);
8336         }
8337       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8338         newConn->insertAtTheEnd(aa,aa+4);
8339     }
8340   if(!addPts->empty())
8341     {
8342       addPts->rearrange(3);
8343       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8344       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8345       ret0->setCoords(addPts);
8346     }
8347   else
8348     {
8349       nbOfAdditionalPoints=0;
8350       ret0->setCoords(getCoords());
8351     }
8352   ret0->setNodalConnectivity(newConn);
8353   //
8354   ret->computeOffsetsFull();
8355   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8356   return ret0.retn();
8357 }
8358
8359 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8360     _own_cell(true),_cell_id(-1),_nb_cell(0)
8361 {
8362   if(mesh)
8363     {
8364       mesh->incrRef();
8365       _nb_cell=mesh->getNumberOfCells();
8366     }
8367 }
8368
8369 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8370 {
8371   if(_mesh)
8372     _mesh->decrRef();
8373   if(_own_cell)
8374     delete _cell;
8375 }
8376
8377 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8378     _own_cell(false),_cell_id(bg-1),
8379     _nb_cell(end)
8380 {
8381   if(mesh)
8382     mesh->incrRef();
8383 }
8384
8385 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8386 {
8387   _cell_id++;
8388   if(_cell_id<_nb_cell)
8389     {
8390       _cell->next();
8391       return _cell;
8392     }
8393   else
8394     return 0;
8395 }
8396
8397 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8398 {
8399   if(_mesh)
8400     _mesh->incrRef();
8401 }
8402
8403 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8404 {
8405   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8406 }
8407
8408 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8409 {
8410   if(_mesh)
8411     _mesh->decrRef();
8412 }
8413
8414 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8415     _itc(itc),
8416     _bg(bg),_end(end)
8417 {
8418   if(_mesh)
8419     _mesh->incrRef();
8420 }
8421
8422 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8423 {
8424   if(_mesh)
8425     _mesh->decrRef();
8426 }
8427
8428 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8429 {
8430   return _type;
8431 }
8432
8433 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8434 {
8435   return _end-_bg;
8436 }
8437
8438 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8439 {
8440   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8441 }
8442
8443 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8444 {
8445   if(mesh)
8446     {
8447       mesh->incrRef();
8448       _nb_cell=mesh->getNumberOfCells();
8449     }
8450 }
8451
8452 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8453 {
8454   if(_mesh)
8455     _mesh->decrRef();
8456   delete _cell;
8457 }
8458
8459 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8460 {
8461   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8462   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8463   if(_cell_id<_nb_cell)
8464     {
8465       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8466       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8467       mcIdType startId=_cell_id;
8468       _cell_id+=nbOfElems;
8469       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8470     }
8471   else
8472     return 0;
8473 }
8474
8475 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8476 {
8477   if(mesh)
8478     {
8479       _conn=mesh->getNodalConnectivity()->getPointer();
8480       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8481     }
8482 }
8483
8484 void MEDCouplingUMeshCell::next()
8485 {
8486   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8487     {
8488       _conn+=_conn_lgth;
8489       _conn_indx++;
8490     }
8491   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8492 }
8493
8494 std::string MEDCouplingUMeshCell::repr() const
8495 {
8496   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8497     {
8498       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8499       oss << " : ";
8500       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8501       return oss.str();
8502     }
8503   else
8504     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8505 }
8506
8507 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8508 {
8509   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8510     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8511   else
8512     return INTERP_KERNEL::NORM_ERROR;
8513 }
8514
8515 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8516 {
8517   lgth=_conn_lgth;
8518   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8519     return _conn;
8520   else
8521     return 0;
8522 }
8523
8524 /// @cond INTERNAL
8525
8526 namespace MEDCouplingImpl
8527 {
8528   const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8529
8530   //================================================================================
8531   /*!
8532    * \brief Encode a cell id and a mesh index into a code
8533    *  \param [in] id - cell id
8534    *  \param [in] iMesh - mesh index [0,1]
8535    *  \return mcIdType - code
8536    */
8537   //================================================================================
8538
8539   mcIdType encodeID( mcIdType id, int iMesh )
8540   {
8541     return ( id + 1 ) * ( iMesh ? -1 : 1 );
8542   }
8543   //================================================================================
8544   /*!
8545    * \brief Return cell id and mesh index by a given id
8546    *  \param [in] id - code of a cell in a mesh
8547    *  \param [out] iMesh - returned mesh index
8548    *  \return mcIdType - cell id
8549    */
8550   //================================================================================
8551
8552   mcIdType decodeID( mcIdType id, int& iMesh )
8553   {
8554     iMesh = ( id < 0 );
8555     return std::abs( id ) - 1;
8556   }
8557
8558   //================================================================================
8559   /*!
8560    * \brief return another face sharing two given nodes of a face edge
8561    *  \param [in] n0 - 1st node of the edge
8562    *  \param [in] n1 - 2nd node of the edge
8563    *  \param [in] inputFaceID - face including \a n0 andf \a n2
8564    *  \param [in] mesh - object and reference meshes
8565    *  \param [in] revNodal - reverse nodal connectivity of the two meshes
8566    *  \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8567    *  \param [out] facesByEdge - return another face including \a n0 andf \a n2
8568    *  \param [out] equalFaces - return faces equal to facesByEdge
8569    */
8570   //================================================================================
8571
8572   void getFacesOfEdge( mcIdType n0,
8573                        mcIdType n1,
8574                        mcIdType inputFaceID,
8575                        MEDCouplingUMesh* mesh[],
8576                        MCAuto<DataArrayIdType> revNodal[],
8577                        MCAuto<DataArrayIdType> revNodalIndx[],
8578                        std::vector< mcIdType >& facesByEdge,
8579                        std::vector< mcIdType >& equalFaces)
8580   {
8581     // find faces sharing the both nodes of edge
8582
8583     facesByEdge.clear();
8584     size_t prevNbF; // nb faces found in 0-th mesh
8585     for ( int iM = 0; iM < 2; ++iM )
8586       {
8587         const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8588         const mcIdType * rev    = revNodal    [ iM ]->begin();
8589
8590         mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8591         mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8592
8593         prevNbF = facesByEdge.size();
8594         facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8595
8596         auto it = std::set_intersection( rev + revInd[ n0 ],
8597                                          rev + revInd[ n0 ] + nbRevFaces0,
8598                                          rev + revInd[ n1 ],
8599                                          rev + revInd[ n1 ] + nbRevFaces1,
8600                                          facesByEdge.begin() + prevNbF );
8601         facesByEdge.resize( it - facesByEdge.begin() );
8602       }
8603
8604     // facesByEdge now contains at least the 'inputFaceID'
8605     // check if there are other faces
8606
8607     size_t nbF = facesByEdge.size();
8608     if ( nbF > 1 )
8609       {
8610         if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8611           {
8612             // remove from facesByEdge equal faces in different meshes
8613             const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8614                                          mesh[1]->getNodalConnectivity()->getConstPointer() };
8615             const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8616                                          mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8617             for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8618               {
8619                 if ( facesByEdge[ i0 ] == theUndefID )
8620                   continue;
8621                 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8622                 bool   isInputFace = ( objFaceID == inputFaceID );
8623
8624                 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8625                   {
8626                     if ( facesByEdge[ i1 ] == theUndefID )
8627                       continue;
8628
8629                     mcIdType f0 = facesByEdge[ i0 ];
8630                     mcIdType f1 = facesByEdge[ i1 ];
8631                     size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8632                     size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8633                     if ( nbNodes0 != nbNodes1 )
8634                       continue;
8635
8636                     const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8637                     const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8638                     if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8639                       {
8640                         // equal faces; remove an object one
8641                         mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8642                         if ( refFaceID == inputFaceID )
8643                           isInputFace = true;
8644
8645                         if ( std::find( equalFaces.begin(),
8646                                         equalFaces.end(), objFaceID ) == equalFaces.end() )
8647                           equalFaces.push_back( objFaceID );
8648
8649                         facesByEdge[ i0 ] = theUndefID;
8650                         if ( isInputFace )
8651                           facesByEdge[ i1 ] = theUndefID;
8652                         break;
8653                       }
8654                   }
8655                 if ( isInputFace )
8656                   facesByEdge[ i0 ] = theUndefID;
8657               }
8658           }
8659       }
8660
8661     nbF = facesByEdge.size();
8662     for ( size_t i = 0; i < facesByEdge.size(); ++i )
8663       {
8664         if ( facesByEdge[ i ] != theUndefID )
8665           {
8666             facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8667             if ( facesByEdge[ i ] == inputFaceID )
8668               facesByEdge[ i ] = theUndefID;
8669           }
8670         nbF -= ( facesByEdge[ i ] == theUndefID );
8671       }
8672
8673     if ( nbF > 1 )
8674       return; // non-manifold
8675
8676     if ( nbF < 1 )
8677       {
8678         facesByEdge.clear();
8679       }
8680     else // nbF == 1, set a found face first
8681       {
8682         if ( facesByEdge[ 0 ] == theUndefID )
8683           {
8684             for ( size_t i = 1; i < facesByEdge.size(); ++i )
8685               if ( facesByEdge[ i ] != theUndefID )
8686                 {
8687                   facesByEdge[ 0 ] = facesByEdge[ i ];
8688                   break;
8689                 }
8690           }
8691         facesByEdge.resize( 1 );
8692       }
8693     return;
8694   }
8695
8696   //================================================================================
8697   /*!
8698    * \brief Remove a face from nodal reversed connectivity
8699    *  \param [in] node - a node of the face
8700    *  \param [in] face - the face
8701    *  \param [in.out] revNodal - reverse nodal connectivity
8702    *  \param [in,out] revNodalIndx - reverse nodal connectivity index
8703    */
8704   //================================================================================
8705
8706   void removeFromRevNodal( mcIdType node,
8707                            mcIdType face,
8708                            MCAuto<DataArrayIdType>& revNodal,
8709                            MCAuto<DataArrayIdType>& revNodalIndx)
8710   {
8711     mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8712     mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8713     auto it = std::find( fBeg, fEnd, face );
8714     if ( it != fEnd )
8715       {
8716         for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8717           *( it2 - 1 ) = *it2;
8718
8719         *( fEnd - 1 ) = theUndefID;
8720       }
8721   }
8722
8723   //================================================================================
8724   /*!
8725    * \brief Check order of two nodes in a given face
8726    *  \param [inout] n0 - node 1
8727    *  \param [inout] n1 - node 2
8728    *  \param [inout] iFEnc - face
8729    *  \param [inout] mesh - mesh
8730    *  \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8731    */
8732   //================================================================================
8733
8734   bool isReverseOrder( mcIdType n0,
8735                        mcIdType n1,
8736                        mcIdType iFEnc,
8737                        MEDCouplingUMesh* mesh[] )
8738   {
8739     int iMesh;
8740     mcIdType iF = decodeID( iFEnc, iMesh );
8741
8742     const mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8743     const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8744
8745     auto it0 = std::find( conn + connI[ iF ] + 1,
8746                           conn + connI[ iF + 1 ],
8747                           n0 );
8748     auto it1 = std::find( conn + connI[ iF ] + 1,
8749                           conn + connI[ iF + 1 ],
8750                           n1 );
8751     long i0 = it0 - conn;
8752     long i1 = it1 - conn;
8753
8754     bool isRev = ( std::abs( i1 - i0 ) == 1 ) ?  i1 < i0 :  i0 < i1;
8755     return isRev;
8756   }
8757
8758   //================================================================================
8759   /*!
8760    * \brief Change orientation of a face in one of given meshes
8761    *  \param [in] iFEnc - face ID also encoding a mesh index
8762    *  \param [in,out] mesh - object and reference meshes
8763    */
8764   //================================================================================
8765
8766   void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8767   {
8768     int iMesh;
8769     mcIdType face = decodeID( iFEnc, iMesh );
8770
8771     mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8772     mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8773
8774     const INTERP_KERNEL::CellModel& cm =
8775       INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8776
8777     cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8778                               (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8779     return;
8780   }
8781 }
8782
8783 /// @endcond
8784
8785 //================================================================================
8786 /*!
8787  * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8788  *  \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8789  *              If there are no cells in \a refFaces or it is nullptr, then any face
8790  *              in \a this mesh is used as a reference
8791  *  \throw If \a this mesh is not well defined.
8792  *  \throw If \a this mesh or \refFaces are not 2D.
8793  *  \throw If \a this mesh and \refFaces do not share nodes.
8794  *  \throw If \a refFaces are not equally oriented.
8795  *  \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8796  *
8797  *  \if ENABLE_EXAMPLES
8798  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8799  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8800  *  \endif
8801  */
8802 //================================================================================
8803
8804 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8805 {
8806   checkConsistencyLight();
8807   if ( getMeshDimension() != 2 )
8808     throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8809   if ( refFaces )
8810     {
8811       refFaces->checkConsistencyLight();
8812       if ( refFaces->getMeshDimension() != 2 )
8813         throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8814       if ( getCoords() != refFaces->getCoords() )
8815         throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8816       if ( refFaces->getNumberOfCells() == 0 )
8817         refFaces = nullptr;
8818     }
8819   if ( getNumberOfCells() == 0 )
8820     return;
8821
8822   enum { _OBJ, _REF };
8823   MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8824   MCAuto<MEDCouplingUMesh> meshPtr;
8825   if ( !mesh[_REF] )
8826     {
8827       meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8828       mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8829       mesh[_REF]->allocateCells(0);
8830       mesh[_REF]->finishInsertingCells();
8831     }
8832   mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8833                                  mesh[_REF]->getNumberOfCells() };
8834   std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8835   isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8836   isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8837
8838   MCAuto<DataArrayIdType> revNodal    [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8839   MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8840   mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8841   mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8842
8843   std::vector< mcIdType > faceNodes(4);
8844   std::vector< mcIdType > facesByEdge(4), equalFaces;
8845   std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8846
8847   while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8848     {
8849       if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8850         {
8851           for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8852             if ( nbFacesToCheck[iMesh] > 0 )
8853               for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8854                 if ( !isFaceQueued[iMesh][f] )
8855                   {
8856                     faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8857                     isFaceQueued[ iMesh ][ f ] = true;
8858                     iMesh = 0;
8859                     break;
8860                   }
8861           if ( faceQueue.empty() )
8862             break;
8863         }
8864
8865       mcIdType fID = faceQueue.back();
8866       faceQueue.pop_back();
8867
8868       int iMesh, iMesh2;
8869       mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8870
8871       nbFacesToCheck[iMesh]--;
8872
8873       equalFaces.clear();
8874       faceNodes.clear();
8875       mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8876       const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8877       const int nbEdges = cm.getNumberOfSons();
8878
8879       // loop on edges of the refFace
8880       mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8881       for ( int edge = 0; edge < nbEdges; ++edge )
8882         {
8883           mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8884
8885           // get faces sharing the edge
8886           MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8887                                            facesByEdge, equalFaces );
8888
8889           if ( facesByEdge.size() > 1 )
8890             THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8891
8892           if ( facesByEdge.size() == 1 )
8893             {
8894               // compare orientation of two faces
8895               //
8896               if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8897                 {
8898                   if ( facesByEdge[0] < 0 ) // in the ref mesh
8899                     throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8900
8901                   MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8902                 }
8903               mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8904               if ( !isFaceQueued[iMesh2][face2] )
8905                 {
8906                   isFaceQueued[iMesh2][face2] = true;
8907                   faceQueue.push_back( facesByEdge[0] );
8908                 }
8909             }
8910           n0 = n1;
8911         }
8912
8913       // remove face and equalFaces from revNodal in order not to treat them again
8914       equalFaces.push_back( fID );
8915       for ( mcIdType face : equalFaces )
8916         {
8917           mcIdType f            = MEDCouplingImpl::decodeID( face, iMesh2 );
8918           const mcIdType *conn  = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8919           const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8920           mcIdType nbNodes      = connI[ f + 1 ] - connI[ f ] - 1;
8921           for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8922
8923             MEDCouplingImpl::removeFromRevNodal( *n, f,  // not to treat f again
8924                                                  revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8925         }
8926
8927     } // while() until all faces checked
8928
8929   return;
8930 }