Salome HOME
[Bug fix] : creation of redundant nodes in BuildSlice3D
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1344  *             precision.
1345  */
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1347 {
1348   checkFullyDefined();
1349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352   coords->recenterForMaxPrecision(eps);
1353   //
1354   mcIdType nbOfCells=getNumberOfCells();
1355   const mcIdType *conn=_nodal_connec->getConstPointer();
1356   const mcIdType *index=_nodal_connec_index->getConstPointer();
1357   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358   connINew->alloc(nbOfCells+1,1);
1359   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1363   bool changed=false;
1364   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1365     {
1366       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1367         {
1368           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1369           changed=true;
1370         }
1371       else
1372         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373       *connINewPtr=connNew->getNumberOfTuples();
1374     }
1375   if(changed)
1376     setConnectivity(connNew,connINew,false);
1377 }
1378
1379 /*!
1380  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382  * the format of the returned DataArrayIdType instance.
1383  *
1384  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1386  */
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1388 {
1389   checkConnectivityFullyDefined();
1390   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392   std::vector<bool> retS(maxElt,false);
1393   computeNodeIdsAlg(retS);
1394   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1395 }
1396
1397 /*!
1398  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1400  */
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1402 {
1403   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404            nbOfCells=getNumberOfCells();
1405   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406   for(mcIdType i=0;i<nbOfCells;i++)
1407     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1408       if(conn[j]>=0)
1409         {
1410           if(conn[j]<nbOfNodes)
1411             nodeIdsInUse[conn[j]]=true;
1412           else
1413             {
1414               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1415               throw INTERP_KERNEL::Exception(oss.str());
1416             }
1417         }
1418 }
1419
1420 /// @cond INTERNAL
1421
1422 struct MEDCouplingAccVisit
1423 {
1424   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426   mcIdType _new_nb_of_nodes;
1427 };
1428
1429 /// @endcond
1430
1431 /*!
1432  * Finds nodes not used in any cell and returns an array giving a new id to every node
1433  * by excluding the unused nodes, for which the array holds -1. The result array is
1434  * a mapping in "Old to New" mode.
1435  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438  *          if the node is unused or a new id else. The caller is to delete this
1439  *          array using decrRef() as it is no more needed.
1440  *  \throw If the coordinates array is not set.
1441  *  \throw If the nodal connectivity of cells is not defined.
1442  *  \throw If the nodal connectivity includes an invalid id.
1443  *
1444  *  \if ENABLE_EXAMPLES
1445  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1447  *  \endif
1448  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1449  */
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1451 {
1452   nbrOfNodesInUse=-1;
1453   mcIdType nbOfNodes(getNumberOfNodes());
1454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455   ret->alloc(nbOfNodes,1);
1456   mcIdType *traducer=ret->getPointer();
1457   std::fill(traducer,traducer+nbOfNodes,-1);
1458   mcIdType nbOfCells=getNumberOfCells();
1459   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460   const mcIdType *conn=_nodal_connec->getConstPointer();
1461   for(mcIdType i=0;i<nbOfCells;i++)
1462     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1463       if(conn[j]>=0)
1464         {
1465           if(conn[j]<nbOfNodes)
1466             traducer[conn[j]]=1;
1467           else
1468             {
1469               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1470               throw INTERP_KERNEL::Exception(oss.str());
1471             }
1472         }
1473   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1475   return ret.retn();
1476 }
1477
1478 /*!
1479  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480  * For each cell in \b this the number of nodes constituting cell is computed.
1481  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482  * So for pohyhedrons some nodes can be counted several times in the returned result.
1483  *
1484  * \return a newly allocated array
1485  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1486  */
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1488 {
1489   checkConnectivityFullyDefined();
1490   mcIdType nbOfCells=getNumberOfCells();
1491   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492   ret->alloc(nbOfCells,1);
1493   mcIdType *retPtr=ret->getPointer();
1494   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1497     {
1498       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499         *retPtr=connI[i+1]-connI[i]-1;
1500       else
1501         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1502     }
1503   return ret.retn();
1504 }
1505
1506 /*!
1507  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1509  *
1510  * \return DataArrayIdType * - new object to be deallocated by the caller.
1511  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1512  */
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1514 {
1515   checkConnectivityFullyDefined();
1516   mcIdType nbOfCells=getNumberOfCells();
1517   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518   ret->alloc(nbOfCells,1);
1519   mcIdType *retPtr=ret->getPointer();
1520   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1523     {
1524       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526         *retPtr=ToIdType(s.size());
1527       else
1528         {
1529           s.erase(-1);
1530           *retPtr=ToIdType(s.size());
1531         }
1532     }
1533   return ret.retn();
1534 }
1535
1536 /*!
1537  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1539  *
1540  * \return a newly allocated array
1541  */
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1543 {
1544   checkConnectivityFullyDefined();
1545   mcIdType nbOfCells=getNumberOfCells();
1546   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547   ret->alloc(nbOfCells,1);
1548   mcIdType *retPtr=ret->getPointer();
1549   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1552     {
1553       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1555     }
1556   return ret.retn();
1557 }
1558
1559 /*!
1560  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562  * array mean that the corresponding old node is no more used.
1563  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564  *           this->getNumberOfNodes() before call of this method. The caller is to
1565  *           delete this array using decrRef() as it is no more needed.
1566  *  \throw If the coordinates array is not set.
1567  *  \throw If the nodal connectivity of cells is not defined.
1568  *  \throw If the nodal connectivity includes an invalid id.
1569  *  \sa areAllNodesFetched
1570  *
1571  *  \if ENABLE_EXAMPLES
1572  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1574  *  \endif
1575  */
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1577 {
1578   return MEDCouplingPointSet::zipCoordsTraducer();
1579 }
1580
1581 /*!
1582  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1584  */
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1586 {
1587   switch(compType)
1588   {
1589     case 0:
1590       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1591     case 1:
1592       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1593     case 2:
1594       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1595     case 3:
1596       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1597     case 7:
1598       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1599   }
1600   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1610   return 0;
1611 }
1612
1613 /*!
1614  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1615  */
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1617 {
1618   mcIdType sz=connI[cell1+1]-connI[cell1];
1619   if(sz==connI[cell2+1]-connI[cell2])
1620     {
1621       if(conn[connI[cell1]]==conn[connI[cell2]])
1622         {
1623           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624           unsigned dim=cm.getDimension();
1625           if(dim!=3)
1626             {
1627               if(dim!=1)
1628                 {
1629                   mcIdType sz1=2*(sz-1);
1630                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634                   return work!=tmp+sz1?1:0;
1635                 }
1636               else
1637                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1638             }
1639           else
1640             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1641         }
1642     }
1643   return 0;
1644 }
1645
1646 /*!
1647  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1648  */
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1650 {
1651   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1652     {
1653       if(conn[connI[cell1]]==conn[connI[cell2]])
1654         {
1655           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1657           return s1==s2?1:0;
1658         }
1659     }
1660   return 0;
1661 }
1662
1663 /*!
1664  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1665  */
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1667 {
1668   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1669     {
1670       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1672       return s1==s2?1:0;
1673     }
1674   return 0;
1675 }
1676
1677 /*!
1678  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1679  */
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1681 {
1682   mcIdType sz=connI[cell1+1]-connI[cell1];
1683   if(sz==connI[cell2+1]-connI[cell2])
1684     {
1685       if(conn[connI[cell1]]==conn[connI[cell2]])
1686         {
1687           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688           unsigned dim=cm.getDimension();
1689           if(dim!=3)
1690             {
1691               if(dim!=1)
1692                 {
1693                   mcIdType sz1=2*(sz-1);
1694                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1698                   if(work!=tmp+sz1)
1699                     return 1;
1700                   else
1701                     {
1702                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1705                         return 2;
1706                       else
1707                         return 0;
1708                     }
1709                 }
1710               else
1711                 {//case of SEG2 and SEG3
1712                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1713                     return 1;
1714                   if(!cm.isQuadratic())
1715                     {
1716                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1719                         return 2;
1720                       return 0;
1721                     }
1722                   else
1723                     {
1724                       if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1725                         return 2;
1726                       return 0;
1727                     }
1728                 }
1729             }
1730           else
1731             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 /*!
1739  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741  * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743  * This method is time consuming.
1744  *
1745  * \param [in] compType input specifying the technique used to compare cells each other.
1746  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750  * can be used for users not sensitive to orientation of cell
1751  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1754  *
1755  */
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1757 {
1758   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759   getReverseNodalConnectivity(revNodal,revNodalI);
1760   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1761 }
1762
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1765 {
1766   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771   std::vector<bool> isFetched(nbOfCells,false);
1772   if(startCellId==0)
1773     {
1774       for(mcIdType i=startCellId;i<nbOfCells;i++)
1775         {
1776           if(!isFetched[i])
1777             {
1778               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779               std::vector<mcIdType> v,v2;
1780               if(connOfNode!=connPtr+connIPtr[i+1])
1781                 {
1782                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1784                   connOfNode++;
1785                 }
1786               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1787                 if(*connOfNode>=0)
1788                   {
1789                     v=v2;
1790                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792                     v2.resize(std::distance(v2.begin(),it));
1793                   }
1794               if(v2.size()>1)
1795                 {
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType pos=commonCellsI->back();
1799                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   else
1808     {
1809       for(mcIdType i=startCellId;i<nbOfCells;i++)
1810         {
1811           if(!isFetched[i])
1812             {
1813               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815               std::vector<mcIdType> v,v2;
1816               if(connOfNode!=connPtr+connIPtr[i+1])
1817                 {
1818                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1819                   connOfNode++;
1820                 }
1821               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1822                 if(*connOfNode>=0)
1823                   {
1824                     v=v2;
1825                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826                     v2.resize(std::distance(v2.begin(),it));
1827                   }
1828               // v2 contains now candidates. Problem candidates are sorted using id rank.
1829               if(v2.size()>1)
1830                 {
1831                   if(v2[0]!=i)
1832                   {
1833                     auto it(std::find(v2.begin(),v2.end(),i));
1834                     std::swap(*v2.begin(),*it);
1835                   }
1836                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1837                     {
1838                       mcIdType newPos(commonCells->getNumberOfTuples());
1839                       mcIdType pos(commonCellsI->back());
1840                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841                       commonCellsI->pushBackSilent(newPos);
1842                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843                         isFetched[*it]=true;
1844                     }
1845                 }
1846             }
1847         }
1848     }
1849   commonCellsArr=commonCells.retn();
1850   commonCellsIArr=commonCellsI.retn();
1851 }
1852
1853 /*!
1854  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856  * than \a this->getNumberOfCells() in the returned array means that there is no
1857  * corresponding cell in \a this mesh.
1858  * It is expected that \a this and \a other meshes share the same node coordinates
1859  * array, if it is not so an exception is thrown.
1860  *  \param [in] other - the mesh to compare with.
1861  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1862  *         valid values [0,1,2], see zipConnectivityTraducer().
1863  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1865  *         values. The caller is to delete this array using
1866  *         decrRef() as it is no more needed.
1867  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1868  *         mesh.
1869  *
1870  *  \if ENABLE_EXAMPLES
1871  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1873  *  \endif
1874  *  \sa checkDeepEquivalOnSameNodesWith()
1875  *  \sa checkGeoEquivalWith()
1876  */
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1878 {
1879   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880   mcIdType nbOfCells=getNumberOfCells();
1881   static const int possibleCompType[]={0,1,2};
1882   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1883     {
1884       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1886       oss << " !";
1887       throw INTERP_KERNEL::Exception(oss.str());
1888     }
1889   //
1890   if(other->getNumberOfCells()==0)
1891   {
1892     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1893     return true;
1894   }
1895   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898   mcIdType newNbOfCells=-1;
1899   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901   mcIdType maxPart(p0->getMaxValueInArray());
1902   bool ret(maxPart==newNbOfCells-1);
1903   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904   // fill p1 array in case of presence of cells in other not in this
1905   mcIdType *pt(p1->getPointer());
1906   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1907     pt[i+1] = i+1;
1908   //
1909   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1911   arr = p2.retn();
1912   return ret;
1913 }
1914
1915 /*!
1916  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917  * This method tries to determine if \b other is fully included in \b this.
1918  * The main difference is that this method is not expected to throw exception.
1919  * This method has two outputs :
1920  *
1921  * \param other other mesh
1922  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1924  */
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1926 {
1927   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928   DataArrayIdType *commonCells=0,*commonCellsI=0;
1929   mcIdType thisNbCells=getNumberOfCells();
1930   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933   mcIdType otherNbCells=other->getNumberOfCells();
1934   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935   arr2->alloc(otherNbCells,1);
1936   arr2->fillWithZero();
1937   mcIdType *arr2Ptr=arr2->getPointer();
1938   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939   for(mcIdType i=0;i<nbOfCommon;i++)
1940     {
1941       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942       if(start<thisNbCells)
1943         {
1944           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1945             {
1946               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947               mcIdType val=std::abs(commonCellsPtr[j])-1;
1948               if(val>=thisNbCells)
1949                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1950             }
1951         }
1952     }
1953   arr2->setName(other->getName());
1954   if(arr2->presenceOfValue(0))
1955     return false;
1956   arr=arr2.retn();
1957   return true;
1958 }
1959
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1961 {
1962   if(!other)
1963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1965   if(!otherC)
1966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967   std::vector<const MEDCouplingUMesh *> ms(2);
1968   ms[0]=this;
1969   ms[1]=otherC;
1970   return MergeUMeshesOnSameCoords(ms);
1971 }
1972
1973 /*!
1974  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976  * cellIds is not given explicitly but by a range python like.
1977  *
1978  * \param start starting ID
1979  * \param end end ID (excluded)
1980  * \param step step size
1981  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982  * \return a newly allocated
1983  *
1984  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1986  */
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1988 {
1989   if(getMeshDimension()!=-1)
1990     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1991   else
1992     {
1993       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1994       if(newNbOfCells!=1)
1995         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1996       if(start!=0)
1997         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1998       incrRef();
1999       return const_cast<MEDCouplingUMesh *>(this);
2000     }
2001 }
2002
2003 /*!
2004  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005  * The result mesh shares or not the node coordinates array with \a this mesh depending
2006  * on \a keepCoords parameter.
2007  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008  *           to write this mesh to the MED file, its cells must be sorted using
2009  *           sortCellsInMEDFileFrmt().
2010  *  \param [in] begin - an array of cell ids to include to the new mesh.
2011  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2014  *         by calling zipCoords().
2015  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016  *         to delete this mesh using decrRef() as it is no more needed.
2017  *  \throw If the coordinates array is not set.
2018  *  \throw If the nodal connectivity of cells is not defined.
2019  *  \throw If any cell id in the array \a begin is not valid.
2020  *
2021  *  \if ENABLE_EXAMPLES
2022  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2024  *  \endif
2025  */
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2027 {
2028   if(getMeshDimension()!=-1)
2029     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2030   else
2031     {
2032       if(end-begin!=1)
2033         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2034       if(begin[0]!=0)
2035         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2036       incrRef();
2037       return const_cast<MEDCouplingUMesh *>(this);
2038     }
2039 }
2040
2041 /*!
2042  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2043  *
2044  * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046  * The number of cells of \b this will remain the same with this method.
2047  *
2048  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050  * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2052  */
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2054 {
2055   checkConnectivityFullyDefined();
2056   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2060     {
2061       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063       throw INTERP_KERNEL::Exception(oss.str());
2064     }
2065   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069       throw INTERP_KERNEL::Exception(oss.str());
2070     }
2071   mcIdType nbOfCells(getNumberOfCells());
2072   bool easyAssign(true);
2073   const mcIdType *connI(_nodal_connec_index->begin());
2074   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2076     {
2077       if(*it>=0 && *it<nbOfCells)
2078         {
2079           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2080         }
2081       else
2082         {
2083           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084           throw INTERP_KERNEL::Exception(oss.str());
2085         }
2086     }
2087   if(easyAssign)
2088     {
2089       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2090       computeTypes();
2091     }
2092   else
2093     {
2094       DataArrayIdType *arrOut=0,*arrIOut=0;
2095       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2096                                                arrOut,arrIOut);
2097       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098       setConnectivity(arrOut,arrIOut,true);
2099     }
2100 }
2101
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2103 {
2104   checkConnectivityFullyDefined();
2105   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2109     {
2110       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112       throw INTERP_KERNEL::Exception(oss.str());
2113     }
2114   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118       throw INTERP_KERNEL::Exception(oss.str());
2119     }
2120   mcIdType nbOfCells=getNumberOfCells();
2121   bool easyAssign=true;
2122   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2124   mcIdType it=start;
2125   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2126     {
2127       if(it>=0 && it<nbOfCells)
2128         {
2129           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2130         }
2131       else
2132         {
2133           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134           throw INTERP_KERNEL::Exception(oss.str());
2135         }
2136     }
2137   if(easyAssign)
2138     {
2139       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2140       computeTypes();
2141     }
2142   else
2143     {
2144       DataArrayIdType *arrOut=0,*arrIOut=0;
2145       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2146                                                 arrOut,arrIOut);
2147       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148       setConnectivity(arrOut,arrIOut,true);
2149     }
2150 }
2151
2152
2153 /*!
2154  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155  * this->getMeshDimension(), that bound some cells of \a this mesh.
2156  * The cells of lower dimension to include to the result mesh are selected basing on
2157  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160  * created mesh shares the node coordinates array with \a this mesh.
2161  *  \param [in] begin - the array of node ids.
2162  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164  *         array \a begin are added, else cells whose any node is in the
2165  *         array \a begin are added.
2166  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167  *         to delete this mesh using decrRef() as it is no more needed.
2168  *  \throw If the coordinates array is not set.
2169  *  \throw If the nodal connectivity of cells is not defined.
2170  *  \throw If any node id in \a begin is not valid.
2171  *
2172  *  \if ENABLE_EXAMPLES
2173  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2175  *  \endif
2176  */
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2178 {
2179   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2184 }
2185
2186 /*!
2187  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2191  *         by calling zipCoords().
2192  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193  *         to delete this mesh using decrRef() as it is no more needed.
2194  *  \throw If the coordinates array is not set.
2195  *  \throw If the nodal connectivity of cells is not defined.
2196  *
2197  *  \if ENABLE_EXAMPLES
2198  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2200  *  \endif
2201  */
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2203 {
2204   DataArrayIdType *desc=DataArrayIdType::New();
2205   DataArrayIdType *descIndx=DataArrayIdType::New();
2206   DataArrayIdType *revDesc=DataArrayIdType::New();
2207   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2208   //
2209   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2210   revDesc->decrRef();
2211   desc->decrRef();
2212   descIndx->decrRef();
2213   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215   std::vector<mcIdType> boundaryCells;
2216   for(mcIdType i=0;i<nbOfCells;i++)
2217     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218       boundaryCells.push_back(i);
2219   revDescIndx->decrRef();
2220   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2221   return ret;
2222 }
2223
2224 /*!
2225  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2228  */
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2230 {
2231   checkFullyDefined();
2232   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2236   //
2237   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2239   //
2240   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242   const mcIdType *revDescPtr=revDesc->getConstPointer();
2243   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244   mcIdType nbOfCells=getNumberOfCells();
2245   std::vector<bool> ret1(nbOfCells,false);
2246   mcIdType sz=0;
2247   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2250   //
2251   DataArrayIdType *ret2=DataArrayIdType::New();
2252   ret2->alloc(sz,1);
2253   mcIdType *ret2Ptr=ret2->getPointer();
2254   sz=0;
2255   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2256     if(*it)
2257       *ret2Ptr++=sz;
2258   ret2->setName("BoundaryCells");
2259   return ret2;
2260 }
2261
2262 /*!
2263  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2267  *
2268  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269  * 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
2270  * equals a cell in \b otherDimM1OnSameCoords.
2271  *
2272  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2274  *
2275  * \param [in] otherDimM1OnSameCoords other mesh
2276  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277  * \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
2278  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2279  */
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2281 {
2282   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284   checkConnectivityFullyDefined();
2285   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294   DataArrayIdType *idsOtherInConsti=0;
2295   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2297   if(!b)
2298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299   std::set<mcIdType> s1;
2300   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303   s1arr_renum1->sort();
2304   cellIdsRk0=s0arr.retn();
2305   //cellIdsRk1=s_renum1.retn();
2306   cellIdsRk1=s1arr_renum1.retn();
2307 }
2308
2309 /*!
2310  * 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
2311  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2312  *
2313  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2314  */
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2316 {
2317   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2321   //
2322   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323   revDesc=0; desc=0; descIndx=0;
2324   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2327 }
2328
2329 /*!
2330  * Finds nodes lying on the boundary of \a this mesh.
2331  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332  *          nodes. The caller is to delete this array using decrRef() as it is no
2333  *          more needed.
2334  *  \throw If the coordinates array is not set.
2335  *  \throw If the nodal connectivity of cells is node defined.
2336  *
2337  *  \if ENABLE_EXAMPLES
2338  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2340  *  \endif
2341  */
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2343 {
2344   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345   return skin->computeFetchedNodeIds();
2346 }
2347
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2349 {
2350   incrRef();
2351   return const_cast<MEDCouplingUMesh *>(this);
2352 }
2353
2354 /*!
2355  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2358  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2359  * 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.
2360  *
2361  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2362  *             parameter is altered during the call.
2363  * \return node ids which need to be duplicated following the algorithm explained above.
2364  *
2365  */
2366 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords) const
2367 {
2368   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2369   // which mimicks the C++
2370   using DAInt = MCAuto<DataArrayIdType>;
2371   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2372
2373   checkFullyDefined();
2374   otherDimM1OnSameCoords.checkFullyDefined();
2375   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2376     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2377   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2378     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2379
2380   // Checking star-shaped M1 group:
2381   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2382   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2383   DAInt dsi = rdit0->deltaShiftIndex();
2384   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.
2385   if(idsTmp0->getNumberOfTuples())
2386     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2387   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2388
2389   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2390   // ie nodes belonging to the boundary "cells" (might be points) of M1
2391   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2392   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2393   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2394   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2395   dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2396   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2397   dsi = rdit0->deltaShiftIndex();  rdit0=0;
2398   DAInt boundSegs = dsi->findIdsEqual(1);  dsi = 0; // boundary segs/faces of the M0 mesh
2399   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2400   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2401   // 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)
2402   // 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
2403   // although they are technically on the skin of the cube.
2404   DAInt notDup = 0;
2405   if (getMeshDimension() == 3)
2406     {
2407       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2408       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2409       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2410       DataArrayIdType * corresp=0;
2411       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2412       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2413       // In the cube example above, this is a U shape polyline.
2414       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2415       corresp->decrRef();
2416       if (validIds->getNumberOfTuples())
2417         {
2418           // 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:
2419           // (the U-shaped polyline described above)
2420           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2421           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2422           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2423           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2424
2425           // Specific logic to handle singular points :
2426           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2427           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2428           //   algorithm would be duplicating too much ...
2429           // 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:
2430           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2431           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2432           dnu1=0;dnu2=0;dnu3=0;
2433           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2434           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2435           if (singPoints->getNumberOfTuples())
2436             {
2437               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2438               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2439               // should not be duplicated
2440               //    1. Extract N D cells touching U-shape line:
2441               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2442               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2443               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2444               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2445               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2446               DataArrayIdType *idsOfM1BNt;
2447               mAroundBNDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1BNt);
2448               DAInt idsOfM1BN(idsOfM1BNt);
2449               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2450               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2451               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2452               for(const auto& v: *idsOfM1BN)
2453                 {
2454                   if (v >= nCellsDesc)    // Keep valid match only
2455                     continue;
2456                   mcIdType idx0 = revDescIBNP[v];
2457                   // Keep the two cells on either side of the face v of M1:
2458                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2459                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2460                 }
2461               //    3. Build complement
2462               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2463               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2464               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2465               DAInt inters = boundNodes->buildIntersection(nod3);
2466               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2467             }
2468           notDup = xtrem->buildSubstraction(fNodes1);
2469         }
2470       else  // if (validIds-> ...)
2471         notDup = xtrem->buildSubstraction(fNodes);
2472     }
2473   else  // if (3D ...)
2474     notDup = xtrem->buildSubstraction(fNodes);
2475
2476   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2477   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2478   return dupl.retn();
2479 }
2480
2481
2482 /*!
2483  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2484  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2485  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2486  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2487  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2488  *
2489  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2490  *             parameter is altered during the call.
2491  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2492  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2493  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2494  * \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.
2495  *
2496  */
2497 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2498                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2499 {
2500   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2501   // which mimicks the C++
2502   using DAInt = MCAuto<DataArrayIdType>;
2503   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2504
2505   checkFullyDefined();
2506   otherDimM1OnSameCoords.checkFullyDefined();
2507   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2508     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2509   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2510     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2511
2512   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2513
2514   //
2515   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2516   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2517   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2518   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2519
2520   // Extract now all N D cells which have a complete face in touch with the group:
2521   //   1. Identify cells of M1 group in sub-mesh mAroundGrp
2522   DataArrayIdType *idsOfM1t;
2523   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2524   DAInt idsOfM1Large(idsOfM1t);
2525   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2526   DAInt idsStrict = DataArrayIdType::New(); idsStrict->alloc(0,1);
2527   //  2. Build map giving for each cell ID in mAroundGrp (not in mAroundGrpLarge) the corresponding cell
2528   //     ID on the other side of the crack:
2529   std::map<mcIdType, mcIdType> toOtherSide, pos;
2530   mcIdType cnt = 0;
2531   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2532   for(const auto& v: *idsOfM1Large)
2533     {
2534       if (v >= nL)    // Keep valid match only
2535         continue;
2536       mcIdType idx0 = revDescILP[v];
2537       // Keep the two cells on either side of the face v of M1:
2538       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2539       DAInt t1=idsStrict->findIdsEqual(c1), t2=idsStrict->findIdsEqual(c2);
2540
2541       if (!t1->getNumberOfTuples())
2542         {  pos[c1] = cnt++; idsStrict->pushBackSilent(c1);   }
2543       if (!t2->getNumberOfTuples())
2544         {  pos[c2] = cnt++; idsStrict->pushBackSilent(c2);   }
2545
2546       mcIdType k1 = pos[c1], k2=pos[c2];
2547       toOtherSide[k1] = k2;
2548       toOtherSide[k2] = k1;
2549     }
2550
2551   DAInt cellsAroundGroup = cellsAroundGroupLarge->selectByTupleId(idsStrict->begin(), idsStrict->end());
2552   MCUMesh mAroundGrp = static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(), cellsAroundGroup->end(), true));
2553   mcIdType nCells=cellsAroundGroup->getNumberOfTuples(), nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2554   DAInt desc=DataArrayIdType::New(),descI=DataArrayIdType::New(),revDesc=DataArrayIdType::New(),revDescI=DataArrayIdType::New();  
2555   MCUMesh mArGrpDesc=mAroundGrp->buildDescendingConnectivity(desc,descI,revDesc,revDescI);
2556   DataArrayIdType *idsOfM1t2;
2557   mArGrpDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t2);  // TODO can we avoid recomputation here?
2558   DAInt idsOfM1(idsOfM1t2);
2559
2560   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2561   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2562   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2563   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1->begin(), idsOfM1->end(),desc,descI);
2564   //     Compute the neighbor of each cell in mAroundGrp, taking into account the broken link above. Two
2565   //     cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2566   DataArrayIdType *neight=0, *neighIt=0;
2567   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc,descI,revDesc,revDescI, neight, neighIt);
2568   DAInt neigh(neight), neighI(neighIt);
2569
2570   // For each initial connex part of the M1 mesh (or said differently for each independent crack):
2571   mcIdType seed=0, nIter=0;
2572   mcIdType nIterMax = nCells+1; // Safety net for the loop
2573   DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells,1);
2574   mcIdType* hitCellsP = hitCells->rwBegin();
2575   hitCells->fillWithValue(0);  // 0 : not hit, +x: one side of the crack, -x: other side of the crack, with 'x' the index of the connex component
2576   mcIdType PING_FULL, PONG_FULL;
2577   mcIdType MAX_CP = 10000;  // the choices below assume we won't have more than 10000 different connex parts ...
2578   mcIdType PING_FULL_init = 0, PING_PART = MAX_CP;
2579   mcIdType PONG_FULL_init = 0, PONG_PART = -MAX_CP;
2580   cnt=0;
2581   while (nIter < nIterMax)
2582     {
2583       DAInt t = hitCells->findIdsEqual(0);
2584       if(!t->getNumberOfTuples())
2585         break;
2586       mcIdType seed = t->getIJ(0,0);
2587       bool done = false;
2588       cnt++;
2589       PING_FULL = PING_FULL_init+cnt;
2590       PONG_FULL = PONG_FULL_init-cnt;
2591       // while the connex bits in correspondance on either side of the crack are not fully covered
2592       while(!done && nIter < nIterMax)  // Start of the ping-pong
2593         {
2594           nIter++;
2595           // Identify connex zone around the seed - this zone corresponds to some cells on the other side
2596           // of the crack that might extend further away. So we will need to compute spread zone on the other side
2597           // too ... and this process can repeat, hence the "ping-pong" logic.
2598           mcIdType dnu;
2599           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh,neighI, -1, dnu);
2600           done = true;
2601           for(const mcIdType& s: *spreadZone)
2602             {
2603               hitCellsP[s] = PING_FULL;
2604               const auto& it = toOtherSide.find(s);
2605               if (it != toOtherSide.end())
2606                 {
2607                   mcIdType other = it->second;
2608                   if (hitCellsP[other] != PONG_FULL)
2609                     {
2610                       // On the other side of the crack we hit a cell which was not fully covered previously by the 
2611                       // ComputeSpreadZone process, so we are not done yet, ComputeSreadZone will need to be applied there
2612                       done = false;
2613                       hitCellsP[other] = PONG_PART;
2614                       //  Compute next seed, i.e. a cell on the other side of the crack
2615                       seed = other;
2616                     }
2617                 }
2618             }
2619           if (done)
2620             {
2621               // we might have several disjoint PONG parts in front of a single PING connex part:
2622               DAInt idsPong = hitCells->findIdsEqual(PONG_PART);
2623               if (idsPong->getNumberOfTuples())
2624                 {
2625                   seed = idsPong->getIJ(0,0);
2626                   done = false;
2627                 }
2628               continue;  // continue without switching side (or break if 'done' remains false)
2629             }
2630           else
2631             {
2632               // Go to the other side
2633               std::swap(PING_FULL, PONG_FULL);
2634               std::swap(PING_PART, PONG_PART);
2635             }
2636         } // while (!done ...)
2637       DAInt nonHitCells = hitCells->findIdsEqual(0);
2638       if (nonHitCells->getNumberOfTuples())
2639         seed = nonHitCells->getIJ(0,0);
2640       else
2641         break;
2642     } // while (nIter < nIterMax ...
2643   if (nIter >= nIterMax)
2644     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Too many iterations - should not happen");
2645
2646   // Now we have handled all N D cells which have a face touching the M1 group. It remains the cells
2647   // which are just touching the group by one (or several) node(s) (see for example testBuildInnerBoundaryAlongM1Group4)
2648   // All those cells are in direct contact with a cell which is either PING_FULL or PONG_FULL
2649   // So first reproject the PING/PONG info onto mAroundGrpLarge:
2650   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2651   hitCellsLarge->fillWithValue(0);
2652   mcIdType *hitCellsLargeP=hitCellsLarge->rwBegin(), tt=0;
2653   for(const auto &i: *idsStrict)
2654     { hitCellsLargeP[i] = hitCellsP[tt++]; }
2655   DAInt nonHitCells = hitCellsLarge->findIdsEqual(0);
2656   // Neighbor information in mAroundGrpLarge:
2657   DataArrayIdType *neighLt=0, *neighILt=0;
2658   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descL,descIL,revDescL,revDescIL, neighLt, neighILt);
2659   DAInt neighL(neighLt), neighIL(neighILt);
2660   const mcIdType *neighILP=neighIL->begin(), *neighLP=neighL->begin();
2661   for(const auto& c : *nonHitCells)
2662     {
2663       mcIdType cnt00 = neighILP[c];
2664       for (const mcIdType *n=neighLP+cnt00; cnt00 < neighILP[c+1]; n++, cnt00++)
2665         {
2666           mcIdType neighVal = hitCellsLargeP[*n];
2667           if (neighVal != 0 && std::abs(neighVal) < MAX_CP)  // (@test_T0) second part of the test to skip cells being assigned and target only cells assigned in the first part of the algo above
2668             {
2669               mcIdType currVal = hitCellsLargeP[c];
2670               if (currVal != 0)   // Several neighbors have a candidate number
2671                 {
2672                   // Unfortunately in some weird cases (see testBuildInnerBoundary8) a cell in mAroundGrpLarge
2673                   // might have as neighbor two conflicting spread zone ...
2674                   if (currVal*neighVal < 0)
2675                     {
2676                       // If we arrive here, the cell was already assigned a number and we found a neighbor with
2677                       // a different sign ... we must swap the whole spread zone!!
2678                       DAInt ids1 = hitCellsLarge->findIdsEqual(neighVal), ids1b = hitCellsLarge->findIdsEqual(-neighVal);
2679                       DAInt ids2 = hitCellsLarge->findIdsEqual(MAX_CP*neighVal), ids2b = hitCellsLarge->findIdsEqual(-MAX_CP*neighVal);
2680                       // A nice little lambda to multiply part of a DAInt by -1 ...
2681                       auto mul_part_min1 = [hitCellsLargeP](const DAInt& ids) { for(const auto& i: *ids) hitCellsLargeP[i] *= -1; };
2682                       mul_part_min1(ids1);
2683                       mul_part_min1(ids1b);
2684                       mul_part_min1(ids2);
2685                       mul_part_min1(ids2b);
2686                     }
2687                 }
2688               else  // First assignation
2689                 hitCellsLargeP[c] = MAX_CP*neighVal;  // Same sign, but different value to preserve PING_FULL and PONG_FULL
2690             }
2691         }
2692     }
2693   DAInt cellsRet1 = hitCellsLarge->findIdsInRange(1,MAX_CP*MAX_CP);   // Positive spread zone number
2694   DAInt cellsRet2 = hitCellsLarge->findIdsInRange(-MAX_CP*MAX_CP, 0); // Negative spread zone number
2695
2696   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2697     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2698   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2699   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2700   //
2701   cellIdsNeededToBeRenum=cellsRet1.retn();
2702   cellIdsNotModified=cellsRet2.retn();
2703 }
2704
2705 /*!
2706  * This method operates a modification of the connectivity and coords in \b this.
2707  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2708  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2709  * 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
2710  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2711  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2712  *
2713  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2714  *
2715  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2716  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2717  */
2718 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2719 {
2720   mcIdType nbOfNodes=getNumberOfNodes();
2721   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2722   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2723 }
2724
2725 /*!
2726  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2727  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2728  *
2729  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2730  *
2731  * \sa renumberNodesInConn
2732  */
2733 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2734 {
2735   checkConnectivityFullyDefined();
2736   mcIdType *conn(getNodalConnectivity()->getPointer());
2737   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2738   mcIdType nbOfCells=getNumberOfCells();
2739   for(mcIdType i=0;i<nbOfCells;i++)
2740     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2741       {
2742         mcIdType& node=conn[iconn];
2743         if(node>=0)//avoid polyhedron separator
2744           {
2745             node+=offset;
2746           }
2747       }
2748   _nodal_connec->declareAsNew();
2749   updateTime();
2750 }
2751
2752 /*!
2753  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2754  *  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
2755  *  of a big mesh.
2756  */
2757 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2758 {
2759   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2760 }
2761
2762 /*!
2763  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2764  *  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
2765  *  of a big mesh.
2766  */
2767 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2768 {
2769   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2770 }
2771
2772 /*!
2773  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2774  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2775  * This method is a generalization of shiftNodeNumbersInConn().
2776  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2777  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2778  *         this->getNumberOfNodes(), in "Old to New" mode.
2779  *         See \ref numbering for more info on renumbering modes.
2780  *  \throw If the nodal connectivity of cells is not defined.
2781  *
2782  *  \if ENABLE_EXAMPLES
2783  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2784  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2785  *  \endif
2786  */
2787 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2788 {
2789   checkConnectivityFullyDefined();
2790   mcIdType *conn=getNodalConnectivity()->getPointer();
2791   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2792   mcIdType nbOfCells=getNumberOfCells();
2793   for(mcIdType i=0;i<nbOfCells;i++)
2794     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2795       {
2796         mcIdType& node=conn[iconn];
2797         if(node>=0)//avoid polyhedron separator
2798           {
2799             node=newNodeNumbersO2N[node];
2800           }
2801       }
2802   _nodal_connec->declareAsNew();
2803   updateTime();
2804 }
2805
2806 /*!
2807  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2808  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2809  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2810  *
2811  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2812  */
2813 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2814 {
2815   checkConnectivityFullyDefined();
2816   mcIdType *conn=getNodalConnectivity()->getPointer();
2817   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2818   mcIdType nbOfCells=getNumberOfCells();
2819   for(mcIdType i=0;i<nbOfCells;i++)
2820     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2821       {
2822         mcIdType& node=conn[iconn];
2823         if(node>=0)//avoid polyhedron separator
2824           {
2825             node+=delta;
2826           }
2827       }
2828   _nodal_connec->declareAsNew();
2829   updateTime();
2830 }
2831
2832 /*!
2833  * This method operates a modification of the connectivity in \b this.
2834  * 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.
2835  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2836  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2837  * 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
2838  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2839  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2840  *
2841  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2842  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2843  *
2844  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2845  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2846  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2847  */
2848 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2849 {
2850   checkConnectivityFullyDefined();
2851   std::map<mcIdType,mcIdType> m;
2852   mcIdType val=offset;
2853   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2854     m[*work]=val;
2855   mcIdType *conn=getNodalConnectivity()->getPointer();
2856   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2857   mcIdType nbOfCells=getNumberOfCells();
2858   for(mcIdType i=0;i<nbOfCells;i++)
2859     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2860       {
2861         mcIdType& node=conn[iconn];
2862         if(node>=0)//avoid polyhedron separator
2863           {
2864             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2865             if(it!=m.end())
2866               node=(*it).second;
2867           }
2868       }
2869   updateTime();
2870 }
2871
2872 /*!
2873  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2874  *
2875  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2876  * After the call of this method the number of cells remains the same as before.
2877  *
2878  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2879  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2880  * be strictly in [0;this->getNumberOfCells()).
2881  *
2882  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2883  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2884  * should be contained in[0;this->getNumberOfCells()).
2885  *
2886  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2887  * \param check whether to check content of old2NewBg
2888  */
2889 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2890 {
2891   checkConnectivityFullyDefined();
2892   mcIdType nbCells=getNumberOfCells();
2893   const mcIdType *array=old2NewBg;
2894   if(check)
2895     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2896   //
2897   const mcIdType *conn=_nodal_connec->getConstPointer();
2898   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2899   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2900   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2901   const mcIdType *n2oPtr=n2o->begin();
2902   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2903   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2904   newConn->copyStringInfoFrom(*_nodal_connec);
2905   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2906   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2907   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2908   //
2909   mcIdType *newC=newConn->getPointer();
2910   mcIdType *newCI=newConnI->getPointer();
2911   mcIdType loc=0;
2912   newCI[0]=loc;
2913   for(mcIdType i=0;i<nbCells;i++)
2914     {
2915       mcIdType pos=n2oPtr[i];
2916       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2917       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2918       loc+=nbOfElts;
2919       newCI[i+1]=loc;
2920     }
2921   //
2922   setConnectivity(newConn,newConnI);
2923   if(check)
2924     free(const_cast<mcIdType *>(array));
2925 }
2926
2927 /*!
2928  * Finds cells whose bounding boxes intersect a given bounding box.
2929  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2930  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2931  *         zMax (if in 3D).
2932  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2933  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2934  *         extent of the bounding box of cell to produce an addition to this bounding box.
2935  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2936  *         cells. The caller is to delete this array using decrRef() as it is no more
2937  *         needed.
2938  *  \throw If the coordinates array is not set.
2939  *  \throw If the nodal connectivity of cells is not defined.
2940  *
2941  *  \if ENABLE_EXAMPLES
2942  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2943  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2944  *  \endif
2945  */
2946 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2947 {
2948   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2949   if(getMeshDimension()==-1)
2950     {
2951       elems->pushBackSilent(0);
2952       return elems.retn();
2953     }
2954   int dim=getSpaceDimension();
2955   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2956   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2957   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2958   const double* coords = getCoords()->getConstPointer();
2959   mcIdType nbOfCells=getNumberOfCells();
2960   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2961     {
2962       for (int i=0; i<dim; i++)
2963         {
2964           elem_bb[i*2]=std::numeric_limits<double>::max();
2965           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2966         }
2967
2968       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2969         {
2970           mcIdType node= conn[inode];
2971           if(node>=0)//avoid polyhedron separator
2972             {
2973               for (int idim=0; idim<dim; idim++)
2974                 {
2975                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2976                     {
2977                       elem_bb[idim*2] = coords[node*dim+idim] ;
2978                     }
2979                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2980                     {
2981                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2982                     }
2983                 }
2984             }
2985         }
2986       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2987         elems->pushBackSilent(ielem);
2988     }
2989   return elems.retn();
2990 }
2991
2992 /*!
2993  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2994  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2995  * added in 'elems' parameter.
2996  */
2997 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2998 {
2999   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
3000   if(getMeshDimension()==-1)
3001     {
3002       elems->pushBackSilent(0);
3003       return elems.retn();
3004     }
3005   int dim=getSpaceDimension();
3006   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
3007   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
3008   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
3009   const double* coords = getCoords()->getConstPointer();
3010   mcIdType nbOfCells=getNumberOfCells();
3011   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
3012     {
3013       for (int i=0; i<dim; i++)
3014         {
3015           elem_bb[i*2]=std::numeric_limits<double>::max();
3016           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
3017         }
3018
3019       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3020         {
3021           mcIdType node= conn[inode];
3022           if(node>=0)//avoid polyhedron separator
3023             {
3024               for (int idim=0; idim<dim; idim++)
3025                 {
3026                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
3027                     {
3028                       elem_bb[idim*2] = coords[node*dim+idim] ;
3029                     }
3030                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3031                     {
3032                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
3033                     }
3034                 }
3035             }
3036         }
3037       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3038         elems->pushBackSilent(ielem);
3039     }
3040   return elems.retn();
3041 }
3042
3043 /*!
3044  * Returns a type of a cell by its id.
3045  *  \param [in] cellId - the id of the cell of interest.
3046  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3047  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3048  */
3049 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3050 {
3051   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3052   if(cellId<_nodal_connec_index->getNbOfElems()-1)
3053     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3054   else
3055     {
3056       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3057       throw INTERP_KERNEL::Exception(oss.str());
3058     }
3059 }
3060
3061 /*!
3062  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3063  * This method does not throw exception if geometric type \a type is not in \a this.
3064  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3065  * The coordinates array is not considered here.
3066  *
3067  * \param [in] type the geometric type
3068  * \return cell ids in this having geometric type \a type.
3069  */
3070 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3071 {
3072
3073   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3074   ret->alloc(0,1);
3075   checkConnectivityFullyDefined();
3076   mcIdType nbCells=getNumberOfCells();
3077   int mdim=getMeshDimension();
3078   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3079   if(mdim!=ToIdType(cm.getDimension()))
3080     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3081   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3082   const mcIdType *pt=_nodal_connec->getConstPointer();
3083   for(mcIdType i=0;i<nbCells;i++)
3084     {
3085       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3086         ret->pushBackSilent(i);
3087     }
3088   return ret.retn();
3089 }
3090
3091 /*!
3092  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3093  */
3094 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3095 {
3096   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3097   mcIdType nbOfCells(getNumberOfCells()),ret(0);
3098   for(mcIdType i=0;i<nbOfCells;i++)
3099     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3100       ret++;
3101   return ret;
3102 }
3103
3104 /*!
3105  * Returns the nodal connectivity of a given cell.
3106  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3107  * all returned node ids can be used in getCoordinatesOfNode().
3108  *  \param [in] cellId - an id of the cell of interest.
3109  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3110  *         cleared before the appending.
3111  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3112  */
3113 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3114 {
3115   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3116   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3117     if(*w>=0)
3118       conn.push_back(*w);
3119 }
3120
3121 std::string MEDCouplingUMesh::simpleRepr() const
3122 {
3123   static const char msg0[]="No coordinates specified !";
3124   std::ostringstream ret;
3125   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3126   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3127   int tmpp1,tmpp2;
3128   double tt=getTime(tmpp1,tmpp2);
3129   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3130   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3131   if(_mesh_dim>=-1)
3132     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3133   else
3134     { ret << " Mesh dimension has not been set or is invalid !"; }
3135   if(_coords!=0)
3136     {
3137       const int spaceDim=getSpaceDimension();
3138       ret << spaceDim << "\nInfo attached on space dimension : ";
3139       for(int i=0;i<spaceDim;i++)
3140         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3141       ret << "\n";
3142     }
3143   else
3144     ret << msg0 << "\n";
3145   ret << "Number of nodes : ";
3146   if(_coords!=0)
3147     ret << getNumberOfNodes() << "\n";
3148   else
3149     ret << msg0 << "\n";
3150   ret << "Number of cells : ";
3151   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3152     ret << getNumberOfCells() << "\n";
3153   else
3154     ret << "No connectivity specified !" << "\n";
3155   ret << "Cell types present : ";
3156   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3157     {
3158       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3159       ret << cm.getRepr() << " ";
3160     }
3161   ret << "\n";
3162   return ret.str();
3163 }
3164
3165 std::string MEDCouplingUMesh::advancedRepr() const
3166 {
3167   std::ostringstream ret;
3168   ret << simpleRepr();
3169   ret << "\nCoordinates array : \n___________________\n\n";
3170   if(_coords)
3171     _coords->reprWithoutNameStream(ret);
3172   else
3173     ret << "No array set !\n";
3174   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3175   reprConnectivityOfThisLL(ret);
3176   return ret.str();
3177 }
3178
3179 /*!
3180  * This method returns a C++ code that is a dump of \a this.
3181  * This method will throw if this is not fully defined.
3182  */
3183 std::string MEDCouplingUMesh::cppRepr() const
3184 {
3185   static const char coordsName[]="coords";
3186   static const char connName[]="conn";
3187   static const char connIName[]="connI";
3188   checkFullyDefined();
3189   std::ostringstream ret; ret << "// coordinates" << std::endl;
3190   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3191   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3192   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3193   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3194   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3195   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3196   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3197   return ret.str();
3198 }
3199
3200 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3201 {
3202   std::ostringstream ret;
3203   reprConnectivityOfThisLL(ret);
3204   return ret.str();
3205 }
3206
3207 /*!
3208  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3209  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3210  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3211  * some algos).
3212  *
3213  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3214  * 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
3215  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3216  */
3217 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3218 {
3219   int mdim=getMeshDimension();
3220   if(mdim<0)
3221     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3222   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3223   MCAuto<DataArrayIdType> tmp1,tmp2;
3224   bool needToCpyCT=true;
3225   if(!_nodal_connec)
3226     {
3227       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3228       needToCpyCT=false;
3229     }
3230   else
3231     {
3232       tmp1=_nodal_connec;
3233       tmp1->incrRef();
3234     }
3235   if(!_nodal_connec_index)
3236     {
3237       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3238       needToCpyCT=false;
3239     }
3240   else
3241     {
3242       tmp2=_nodal_connec_index;
3243       tmp2->incrRef();
3244     }
3245   ret->setConnectivity(tmp1,tmp2,false);
3246   if(needToCpyCT)
3247     ret->_types=_types;
3248   if(!_coords)
3249     {
3250       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3251       ret->setCoords(coords);
3252     }
3253   else
3254     ret->setCoords(_coords);
3255   return ret.retn();
3256 }
3257
3258 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3259 {
3260   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3261   const mcIdType *pt=_nodal_connec->getConstPointer();
3262   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3263     return ptI[cellId+1]-ptI[cellId]-1;
3264   else
3265     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3266 }
3267
3268 /*!
3269  * Returns types of cells of the specified part of \a this mesh.
3270  * This method avoids computing sub-mesh explicitly to get its types.
3271  *  \param [in] begin - an array of cell ids of interest.
3272  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3273  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3274  *         describing the cell types.
3275  *  \throw If the coordinates array is not set.
3276  *  \throw If the nodal connectivity of cells is not defined.
3277  *  \sa getAllGeoTypes()
3278  */
3279 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3280 {
3281   checkFullyDefined();
3282   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3283   const mcIdType *conn=_nodal_connec->getConstPointer();
3284   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3285   for(const mcIdType *w=begin;w!=end;w++)
3286     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3287   return ret;
3288 }
3289
3290 /*!
3291  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3292  * Optionally updates
3293  * a set of types of cells constituting \a this mesh.
3294  * This method is for advanced users having prepared their connectivity before. For
3295  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3296  *  \param [in] conn - the nodal connectivity array.
3297  *  \param [in] connIndex - the nodal connectivity index array.
3298  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3299  *         mesh is updated.
3300  */
3301 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3302 {
3303   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3304   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3305   if(isComputingTypes)
3306     computeTypes();
3307   declareAsNew();
3308 }
3309
3310 /*!
3311  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3312  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3313  */
3314 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3315     _nodal_connec(0),_nodal_connec_index(0),
3316     _types(other._types)
3317 {
3318   if(other._nodal_connec)
3319     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3320   if(other._nodal_connec_index)
3321     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3322 }
3323
3324 MEDCouplingUMesh::~MEDCouplingUMesh()
3325 {
3326   if(_nodal_connec)
3327     _nodal_connec->decrRef();
3328   if(_nodal_connec_index)
3329     _nodal_connec_index->decrRef();
3330 }
3331
3332 /*!
3333  * Recomputes a set of cell types of \a this mesh. For more info see
3334  * \ref MEDCouplingUMeshNodalConnectivity.
3335  */
3336 void MEDCouplingUMesh::computeTypes()
3337 {
3338   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3339 }
3340
3341
3342 /*!
3343  * Returns a number of cells constituting \a this mesh.
3344  *  \return mcIdType - the number of cells in \a this mesh.
3345  *  \throw If the nodal connectivity of cells is not defined.
3346  */
3347 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3348 {
3349   if(_nodal_connec_index)
3350     return _nodal_connec_index->getNumberOfTuples()-1;
3351   else
3352     if(_mesh_dim==-1)
3353       return 1;
3354     else
3355       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3356 }
3357
3358 /*!
3359  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3360  * mesh. For more info see \ref meshes.
3361  *  \return int - the dimension of \a this mesh.
3362  *  \throw If the mesh dimension is not defined using setMeshDimension().
3363  */
3364 int MEDCouplingUMesh::getMeshDimension() const
3365 {
3366   if(_mesh_dim<-1)
3367     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3368   return _mesh_dim;
3369 }
3370
3371 /*!
3372  * Returns a length of the nodal connectivity array.
3373  * This method is for test reason. Normally the integer returned is not useable by
3374  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3375  *  \return mcIdType - the length of the nodal connectivity array.
3376  */
3377 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3378 {
3379   return _nodal_connec->getNbOfElems();
3380 }
3381
3382 /*!
3383  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3384  */
3385 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3386 {
3387   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3388   tinyInfo.push_back(ToIdType(getMeshDimension()));
3389   tinyInfo.push_back(getNumberOfCells());
3390   if(_nodal_connec)
3391     tinyInfo.push_back(getNodalConnectivityArrayLen());
3392   else
3393     tinyInfo.push_back(-1);
3394 }
3395
3396 /*!
3397  * First step of unserialization process.
3398  */
3399 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3400 {
3401   return tinyInfo[6]<=0;
3402 }
3403
3404 /*!
3405  * Second step of serialization process.
3406  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3407  * \param a1 DataArrayDouble
3408  * \param a2 DataArrayDouble
3409  * \param littleStrings string vector
3410  */
3411 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3412 {
3413   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3414   if(tinyInfo[5]!=-1)
3415     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3416 }
3417
3418 /*!
3419  * Third and final step of serialization process.
3420  */
3421 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3422 {
3423   MEDCouplingPointSet::serialize(a1,a2);
3424   if(getMeshDimension()>-1)
3425     {
3426       a1=DataArrayIdType::New();
3427       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3428       mcIdType *ptA1=a1->getPointer();
3429       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3430       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3431       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3432       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3433     }
3434   else
3435     a1=0;
3436 }
3437
3438 /*!
3439  * Second and final unserialization process.
3440  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3441  */
3442 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3443 {
3444   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3445   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3446   if(tinyInfo[7]!=-1)
3447     {
3448       // Connectivity
3449       const mcIdType *recvBuffer=a1->getConstPointer();
3450       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3451       myConnecIndex->alloc(tinyInfo[6]+1,1);
3452       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3453       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3454       myConnec->alloc(tinyInfo[7],1);
3455       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3456       setConnectivity(myConnec, myConnecIndex);
3457     }
3458 }
3459
3460
3461
3462 /*!
3463  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3464  * mesh.<br>
3465  * For 1D cells, the returned field contains lengths.<br>
3466  * For 2D cells, the returned field contains areas.<br>
3467  * For 3D cells, the returned field contains volumes.
3468  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3469  *         orientation, i.e. the volume is always positive.
3470  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3471  *         and one time . The caller is to delete this field using decrRef() as it is no
3472  *         more needed.
3473  */
3474 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3475 {
3476   std::string name="MeasureOfMesh_";
3477   name+=getName();
3478   mcIdType nbelem=getNumberOfCells();
3479   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3480   field->setName(name);
3481   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3482   array->alloc(nbelem,1);
3483   double *area_vol=array->getPointer();
3484   field->setArray(array) ; array=0;
3485   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3486   field->synchronizeTimeWithMesh();
3487   if(getMeshDimension()!=-1)
3488     {
3489       mcIdType ipt;
3490       INTERP_KERNEL::NormalizedCellType type;
3491       int dim_space=getSpaceDimension();
3492       const double *coords=getCoords()->getConstPointer();
3493       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3494       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3495       for(mcIdType iel=0;iel<nbelem;iel++)
3496         {
3497           ipt=connec_index[iel];
3498           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3499           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);
3500         }
3501       if(isAbs)
3502         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3503     }
3504   else
3505     {
3506       area_vol[0]=std::numeric_limits<double>::max();
3507     }
3508   return field.retn();
3509 }
3510
3511 /*!
3512  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3513  * mesh.<br>
3514  * For 1D cells, the returned array contains lengths.<br>
3515  * For 2D cells, the returned array contains areas.<br>
3516  * For 3D cells, the returned array contains volumes.
3517  * This method avoids building explicitly a part of \a this mesh to perform the work.
3518  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3519  *         orientation, i.e. the volume is always positive.
3520  *  \param [in] begin - an array of cell ids of interest.
3521  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3522  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3523  *          delete this array using decrRef() as it is no more needed.
3524  *
3525  *  \if ENABLE_EXAMPLES
3526  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3527  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3528  *  \endif
3529  *  \sa getMeasureField()
3530  */
3531 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3532 {
3533   std::string name="PartMeasureOfMesh_";
3534   name+=getName();
3535   std::size_t nbelem=std::distance(begin,end);
3536   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3537   array->setName(name);
3538   array->alloc(nbelem,1);
3539   double *area_vol=array->getPointer();
3540   if(getMeshDimension()!=-1)
3541     {
3542       mcIdType ipt;
3543       INTERP_KERNEL::NormalizedCellType type;
3544       int dim_space=getSpaceDimension();
3545       const double *coords=getCoords()->getConstPointer();
3546       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3547       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3548       for(const mcIdType *iel=begin;iel!=end;iel++)
3549         {
3550           ipt=connec_index[*iel];
3551           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3552           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3553         }
3554       if(isAbs)
3555         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3556     }
3557   else
3558     {
3559       area_vol[0]=std::numeric_limits<double>::max();
3560     }
3561   return array.retn();
3562 }
3563
3564 /*!
3565  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3566  * \a this one. The returned field contains the dual cell volume for each corresponding
3567  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3568  *  the dual mesh in P1 sens of \a this.<br>
3569  * For 1D cells, the returned field contains lengths.<br>
3570  * For 2D cells, the returned field contains areas.<br>
3571  * For 3D cells, the returned field contains volumes.
3572  * This method is useful to check "P1*" conservative interpolators.
3573  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3574  *         orientation, i.e. the volume is always positive.
3575  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3576  *          nodes and one time. The caller is to delete this array using decrRef() as
3577  *          it is no more needed.
3578  */
3579 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3580 {
3581   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3582   std::string name="MeasureOnNodeOfMesh_";
3583   name+=getName();
3584   mcIdType nbNodes=getNumberOfNodes();
3585   MCAuto<DataArrayDouble> nnpc;
3586   {
3587     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3588     nnpc=tmp2->convertToDblArr();
3589   }
3590   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3591   const double *nnpcPtr(nnpc->begin());
3592   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3593   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3594   array->alloc(nbNodes,1);
3595   double *valsToFill=array->getPointer();
3596   std::fill(valsToFill,valsToFill+nbNodes,0.);
3597   const double *values=tmp->getArray()->getConstPointer();
3598   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3599   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3600   getReverseNodalConnectivity(da,daInd);
3601   const mcIdType *daPtr=da->getConstPointer();
3602   const mcIdType *daIPtr=daInd->getConstPointer();
3603   for(mcIdType i=0;i<nbNodes;i++)
3604     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3605       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3606   ret->setMesh(this);
3607   ret->setArray(array);
3608   return ret.retn();
3609 }
3610
3611 /*!
3612  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3613  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3614  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3615  * and are normalized.
3616  * <br> \a this can be either
3617  * - a  2D mesh in 2D or 3D space or
3618  * - an 1D mesh in 2D space.
3619  *
3620  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3621  *          cells and one time. The caller is to delete this field using decrRef() as
3622  *          it is no more needed.
3623  *  \throw If the nodal connectivity of cells is not defined.
3624  *  \throw If the coordinates array is not set.
3625  *  \throw If the mesh dimension is not set.
3626  *  \throw If the mesh and space dimension is not as specified above.
3627  */
3628 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3629 {
3630   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3631     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3632   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3633   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3634   mcIdType nbOfCells=getNumberOfCells();
3635   int nbComp=getMeshDimension()+1;
3636   array->alloc(nbOfCells,nbComp);
3637   double *vals=array->getPointer();
3638   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3639   const mcIdType *conn=_nodal_connec->getConstPointer();
3640   const double *coords=_coords->getConstPointer();
3641   if(getMeshDimension()==2)
3642     {
3643       if(getSpaceDimension()==3)
3644         {
3645           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3646           const double *locPtr=loc->getConstPointer();
3647           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3648             {
3649               mcIdType offset=connI[i];
3650               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3651               double n=INTERP_KERNEL::norm<3>(vals);
3652               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3653             }
3654         }
3655       else
3656         {
3657           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3658           const double *isAbsPtr=isAbs->getArray()->begin();
3659           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3660             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3661         }
3662     }
3663   else//meshdimension==1
3664     {
3665       double tmp[2];
3666       for(mcIdType i=0;i<nbOfCells;i++)
3667         {
3668           mcIdType offset=connI[i];
3669           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3670           double n=INTERP_KERNEL::norm<2>(tmp);
3671           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3672           *vals++=-tmp[1];
3673           *vals++=tmp[0];
3674         }
3675     }
3676   ret->setArray(array);
3677   ret->setMesh(this);
3678   ret->synchronizeTimeWithSupport();
3679   return ret.retn();
3680 }
3681
3682 /*!
3683  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3684  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3685  * and are normalized.
3686  * <br> \a this can be either
3687  * - a  2D mesh in 2D or 3D space or
3688  * - an 1D mesh in 2D space.
3689  *
3690  * This method avoids building explicitly a part of \a this mesh to perform the work.
3691  *  \param [in] begin - an array of cell ids of interest.
3692  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3693  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3694  *          cells and one time. The caller is to delete this field using decrRef() as
3695  *          it is no more needed.
3696  *  \throw If the nodal connectivity of cells is not defined.
3697  *  \throw If the coordinates array is not set.
3698  *  \throw If the mesh dimension is not set.
3699  *  \throw If the mesh and space dimension is not as specified above.
3700  *  \sa buildOrthogonalField()
3701  *
3702  *  \if ENABLE_EXAMPLES
3703  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3704  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3705  *  \endif
3706  */
3707 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3708 {
3709   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3710     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3711   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3712   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3713   std::size_t nbelems=std::distance(begin,end);
3714   int nbComp=getMeshDimension()+1;
3715   array->alloc(nbelems,nbComp);
3716   double *vals=array->getPointer();
3717   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3718   const mcIdType *conn=_nodal_connec->getConstPointer();
3719   const double *coords=_coords->getConstPointer();
3720   if(getMeshDimension()==2)
3721     {
3722       if(getSpaceDimension()==3)
3723         {
3724           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3725           const double *locPtr=loc->getConstPointer();
3726           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3727             {
3728               mcIdType offset=connI[*i];
3729               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3730               double n=INTERP_KERNEL::norm<3>(vals);
3731               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3732             }
3733         }
3734       else
3735         {
3736           for(std::size_t i=0;i<nbelems;i++)
3737             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3738         }
3739     }
3740   else//meshdimension==1
3741     {
3742       double tmp[2];
3743       for(const mcIdType *i=begin;i!=end;i++)
3744         {
3745           mcIdType offset=connI[*i];
3746           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3747           double n=INTERP_KERNEL::norm<2>(tmp);
3748           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3749           *vals++=-tmp[1];
3750           *vals++=tmp[0];
3751         }
3752     }
3753   ret->setArray(array);
3754   ret->setMesh(this);
3755   ret->synchronizeTimeWithSupport();
3756   return ret.retn();
3757 }
3758
3759 /*!
3760  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3761  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3762  * and are \b not normalized.
3763  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3764  *          cells and one time. The caller is to delete this field using decrRef() as
3765  *          it is no more needed.
3766  *  \throw If the nodal connectivity of cells is not defined.
3767  *  \throw If the coordinates array is not set.
3768  *  \throw If \a this->getMeshDimension() != 1.
3769  *  \throw If \a this mesh includes cells of type other than SEG2.
3770  */
3771 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3772 {
3773   if(getMeshDimension()!=1)
3774     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3775   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3776     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3777   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3778   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3779   mcIdType nbOfCells=getNumberOfCells();
3780   int spaceDim=getSpaceDimension();
3781   array->alloc(nbOfCells,spaceDim);
3782   double *pt=array->getPointer();
3783   const double *coo=getCoords()->getConstPointer();
3784   std::vector<mcIdType> conn;
3785   conn.reserve(2);
3786   for(mcIdType i=0;i<nbOfCells;i++)
3787     {
3788       conn.resize(0);
3789       getNodeIdsOfCell(i,conn);
3790       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3791     }
3792   ret->setArray(array);
3793   ret->setMesh(this);
3794   ret->synchronizeTimeWithSupport();
3795   return ret.retn();
3796 }
3797
3798 /*!
3799  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3800  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3801  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3802  * from. If a result face is shared by two 3D cells, then the face in included twice in
3803  * the result mesh.
3804  *  \param [in] origin - 3 components of a point defining location of the plane.
3805  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3806  *         must be greater than 1e-6.
3807  *  \param [in] eps - half-thickness of the plane.
3808  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3809  *         producing correspondent 2D cells. The caller is to delete this array
3810  *         using decrRef() as it is no more needed.
3811  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3812  *         not share the node coordinates array with \a this mesh. The caller is to
3813  *         delete this mesh using decrRef() as it is no more needed.
3814  *  \throw If the coordinates array is not set.
3815  *  \throw If the nodal connectivity of cells is not defined.
3816  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3817  *  \throw If magnitude of \a vec is less than 1e-6.
3818  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3819  *  \throw If \a this includes quadratic cells.
3820  */
3821 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3822 {
3823   checkFullyDefined();
3824   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3825     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3826   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3827   if(candidates->empty())
3828     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3829   std::vector<mcIdType> nodes;
3830   DataArrayIdType *cellIds1D=0;
3831   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3832   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3833   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3834   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3835   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3836   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3837   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3838   revDesc2=0; revDescIndx2=0;
3839   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3840   revDesc1=0; revDescIndx1=0;
3841   //Marking all 1D cells that contained at least one node located on the plane
3842   //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3843   //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3844   //due to accuracy errors when the needed nodes already exist)
3845   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3846   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3847   //
3848   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3849   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3850     cut3DCurve[*it]=-1;
3851   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3852   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3853   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3854                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3855                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3856   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3857   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3858   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3859   if(cellIds2->empty())
3860     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3861   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3862   ret->setCoords(mDesc1->getCoords());
3863   ret->setConnectivity(conn,connI,true);
3864   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3865   return ret.retn();
3866 }
3867
3868 /*!
3869  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3870 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
3871 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3872 the result mesh.
3873  *  \param [in] origin - 3 components of a point defining location of the plane.
3874  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3875  *         must be greater than 1e-6.
3876  *  \param [in] eps - half-thickness of the plane.
3877  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3878  *         producing correspondent segments. The caller is to delete this array
3879  *         using decrRef() as it is no more needed.
3880  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3881  *         mesh in 3D space. This mesh does not share the node coordinates array with
3882  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3883  *         no more needed.
3884  *  \throw If the coordinates array is not set.
3885  *  \throw If the nodal connectivity of cells is not defined.
3886  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3887  *  \throw If magnitude of \a vec is less than 1e-6.
3888  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3889  *  \throw If \a this includes quadratic cells.
3890  */
3891 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3892 {
3893   checkFullyDefined();
3894   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3895     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3896   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3897   if(candidates->empty())
3898     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3899   std::vector<mcIdType> nodes;
3900   DataArrayIdType *cellIds1D(0);
3901   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3902   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3903   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3904   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3905   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3906   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3907   //
3908   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3909   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3910     cut3DCurve[*it]=-1;
3911   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3912   mcIdType ncellsSub=subMesh->getNumberOfCells();
3913   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3914   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3915                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3916                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3917   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3918   conn->alloc(0,1);
3919   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3920   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3921   for(mcIdType i=0;i<ncellsSub;i++)
3922     {
3923       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3924         {
3925           if(cut3DSurf[i].first!=-2)
3926             {
3927               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3928               connI->pushBackSilent(conn->getNumberOfTuples());
3929               cellIds2->pushBackSilent(i);
3930             }
3931           else
3932             {
3933               mcIdType cellId3DSurf=cut3DSurf[i].second;
3934               mcIdType offset=nodalI[cellId3DSurf]+1;
3935               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3936               for(mcIdType j=0;j<nbOfEdges;j++)
3937                 {
3938                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3939                   connI->pushBackSilent(conn->getNumberOfTuples());
3940                   cellIds2->pushBackSilent(cellId3DSurf);
3941                 }
3942             }
3943         }
3944     }
3945   if(cellIds2->empty())
3946     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3947   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3948   ret->setCoords(mDesc1->getCoords());
3949   ret->setConnectivity(conn,connI,true);
3950   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3951   return ret.retn();
3952 }
3953
3954 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3955 {
3956   checkFullyDefined();
3957   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3958     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3959   if(getNumberOfCells()!=1)
3960     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3961   //
3962   std::vector<mcIdType> nodes;
3963   findNodesOnPlane(origin,vec,eps,nodes);
3964   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());
3965   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3966   revDesc2=0; revDescIndx2=0;
3967   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3968   revDesc1=0; revDescIndx1=0;
3969   DataArrayIdType *cellIds1D(0);
3970   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3971   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3972   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3973   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3974     cut3DCurve[*it]=-1;
3975   bool sameNbNodes;
3976   {
3977     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3978     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3979     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3980   }
3981   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3982   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3983                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3984                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3985   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3986   connI->pushBackSilent(0); conn->alloc(0,1);
3987   {
3988     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3989     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3990     if(cellIds2->empty())
3991       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3992   }
3993   std::vector<std::vector<mcIdType> > res;
3994   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3995   std::size_t sz(res.size());
3996   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3997     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3998   for(std::size_t i=0;i<sz;i++)
3999     {
4000       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
4001       conn->insertAtTheEnd(res[i].begin(),res[i].end());
4002       connI->pushBackSilent(conn->getNumberOfTuples());
4003     }
4004   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4005   ret->setCoords(mDesc1->getCoords());
4006   ret->setConnectivity(conn,connI,true);
4007   mcIdType nbCellsRet(ret->getNumberOfCells());
4008   //
4009   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4010   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4011   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4012   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4013   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4014   MCAuto<DataArrayDouble> occm;
4015   {
4016     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4017     occm=DataArrayDouble::Substract(ccm,pt);
4018   }
4019   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4020   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);
4021   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4022   //
4023   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4024   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4025   ret2->setCoords(mDesc1->getCoords());
4026   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4027   conn2I->pushBackSilent(0); conn2->alloc(0,1);
4028   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4029   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4030   if(dott->getIJ(0,0)>0)
4031     {
4032       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4033       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4034     }
4035   else
4036     {
4037       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4038       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4039     }
4040   for(mcIdType i=1;i<nbCellsRet;i++)
4041     {
4042       if(dott2->getIJ(i,0)<0)
4043         {
4044           if(ciPtr[i+1]-ciPtr[i]>=4)
4045             {
4046               cell0.push_back(-1);
4047               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4048             }
4049         }
4050       else
4051         {
4052           if(ciPtr[i+1]-ciPtr[i]>=4)
4053             {
4054               cell1.push_back(-1);
4055               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4056             }
4057         }
4058     }
4059   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4060   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4061   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4062   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4063   ret2->setConnectivity(conn2,conn2I,true);
4064   ret2->checkConsistencyLight();
4065   ret2->orientCorrectlyPolyhedrons();
4066   return ret2;
4067 }
4068
4069 /*!
4070  * Finds cells whose bounding boxes intersect a given plane.
4071  *  \param [in] origin - 3 components of a point defining location of the plane.
4072  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4073  *         must be greater than 1e-6.
4074  *  \param [in] eps - half-thickness of the plane.
4075  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4076  *         cells. The caller is to delete this array using decrRef() as it is no more
4077  *         needed.
4078  *  \throw If the coordinates array is not set.
4079  *  \throw If the nodal connectivity of cells is not defined.
4080  *  \throw If \a this->getSpaceDimension() != 3.
4081  *  \throw If magnitude of \a vec is less than 1e-6.
4082  *  \sa buildSlice3D()
4083  */
4084 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4085 {
4086   checkFullyDefined();
4087   if(getSpaceDimension()!=3)
4088     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4089   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4090   if(normm<1e-6)
4091     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4092   double vec2[3];
4093   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4094   double angle=acos(vec[2]/normm);
4095   MCAuto<DataArrayIdType> cellIds;
4096   double bbox[6];
4097   if(angle>eps)
4098     {
4099       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4100       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4101       if(normm2/normm>1e-6)
4102         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4103       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4104       mw->setCoords(coo);
4105       mw->getBoundingBox(bbox);
4106       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4107       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4108     }
4109   else
4110     {
4111       getBoundingBox(bbox);
4112       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4113       cellIds=getCellsInBoundingBox(bbox,eps);
4114     }
4115   return cellIds.retn();
4116 }
4117
4118 /*!
4119  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4120  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4121  * No consideration of coordinate is done by this method.
4122  * 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)
4123  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4124  */
4125 bool MEDCouplingUMesh::isContiguous1D() const
4126 {
4127   if(getMeshDimension()!=1)
4128     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4129   mcIdType nbCells=getNumberOfCells();
4130   if(nbCells<1)
4131     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4132   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4133   mcIdType ref=conn[connI[0]+2];
4134   for(mcIdType i=1;i<nbCells;i++)
4135     {
4136       if(conn[connI[i]+1]!=ref)
4137         return false;
4138       ref=conn[connI[i]+2];
4139     }
4140   return true;
4141 }
4142
4143 /*!
4144  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4145  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4146  * \param pt reference point of the line
4147  * \param v normalized director vector of the line
4148  * \param eps max precision before throwing an exception
4149  * \param res output of size this->getNumberOfCells
4150  */
4151 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4152 {
4153   if(getMeshDimension()!=1)
4154     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4155   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4156     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4157   if(getSpaceDimension()!=3)
4158     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4159   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4160   const double *fPtr=f->getArray()->getConstPointer();
4161   double tmp[3];
4162   for(mcIdType i=0;i<getNumberOfCells();i++)
4163     {
4164       const double *tmp1=fPtr+3*i;
4165       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4166       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4167       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4168       double n1=INTERP_KERNEL::norm<3>(tmp);
4169       n1/=INTERP_KERNEL::norm<3>(tmp1);
4170       if(n1>eps)
4171         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4172     }
4173   const double *coo=getCoords()->getConstPointer();
4174   for(mcIdType i=0;i<getNumberOfNodes();i++)
4175     {
4176       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4177       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4178       res[i]=std::accumulate(tmp,tmp+3,0.);
4179     }
4180 }
4181
4182 /*!
4183  * 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.
4184  * \a this is expected to be a mesh so that its space dimension is equal to its
4185  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4186  * 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).
4187  *
4188  * 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
4189  * 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).
4190  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4191  *
4192  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4193  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4194  *
4195  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4196  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4197  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4198  * \return the positive value of the distance.
4199  * \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
4200  * dimension - 1.
4201  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4202  */
4203 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4204 {
4205   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4206   if(meshDim!=spaceDim-1)
4207     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4208   if(meshDim!=2 && meshDim!=1)
4209     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4210   checkFullyDefined();
4211   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4212     { 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()); }
4213   DataArrayIdType *ret1=0;
4214   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4215   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4216   MCAuto<DataArrayIdType> ret1Safe(ret1);
4217   cellId=*ret1Safe->begin();
4218   return *ret0->begin();
4219 }
4220
4221 /*!
4222  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4223  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4224  * 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
4225  * 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).
4226  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4227  *
4228  * \a this is expected to be a mesh so that its space dimension is equal to its
4229  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4230  * 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).
4231  *
4232  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4233  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4234  *
4235  * \param [in] pts the list of points in which each tuple represents a point
4236  * \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.
4237  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4238  * \throw if number of components of \a pts is not equal to the space dimension.
4239  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4240  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4241  */
4242 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4243 {
4244   if(!pts)
4245     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4246   pts->checkAllocated();
4247   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4248   if(meshDim!=spaceDim-1)
4249     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4250   if(meshDim!=2 && meshDim!=1)
4251     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4252   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4253     {
4254       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4255       throw INTERP_KERNEL::Exception(oss.str());
4256     }
4257   checkFullyDefined();
4258   mcIdType nbCells=getNumberOfCells();
4259   if(nbCells==0)
4260     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4261   mcIdType nbOfPts=pts->getNumberOfTuples();
4262   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4263   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4264   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4265   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4266   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4267   const double *bbox(bboxArr->begin());
4268   switch(spaceDim)
4269   {
4270     case 3:
4271       {
4272         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4273         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4274           {
4275             double x=std::numeric_limits<double>::max();
4276             std::vector<mcIdType> elems;
4277             myTree.getMinDistanceOfMax(ptsPtr,x);
4278             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4279             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4280           }
4281         break;
4282       }
4283     case 2:
4284       {
4285         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4286         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4287           {
4288             double x=std::numeric_limits<double>::max();
4289             std::vector<mcIdType> elems;
4290             myTree.getMinDistanceOfMax(ptsPtr,x);
4291             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4292             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4293           }
4294         break;
4295       }
4296     default:
4297       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4298   }
4299   cellIds=ret1.retn();
4300   return ret0.retn();
4301 }
4302
4303 /// @cond INTERNAL
4304
4305 /// @endcond
4306
4307 /*!
4308  * Finds cells in contact with a ball (i.e. a point with precision).
4309  * 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.
4310  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4311  *
4312  * \warning This method is suitable if the caller intends to evaluate only one
4313  *          point, for more points getCellsContainingPoints() is recommended as it is
4314  *          faster.
4315  *  \param [in] pos - array of coordinates of the ball central point.
4316  *  \param [in] eps - ball radius.
4317  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4318  *         if there are no such cells.
4319  *  \throw If the coordinates array is not set.
4320  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4321  */
4322 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4323 {
4324   std::vector<mcIdType> elts;
4325   getCellsContainingPoint(pos,eps,elts);
4326   if(elts.empty())
4327     return -1;
4328   return elts.front();
4329 }
4330
4331 /*!
4332  * Finds cells in contact with a ball (i.e. a point with precision).
4333  * 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.
4334  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4335  * \warning This method is suitable if the caller intends to evaluate only one
4336  *          point, for more points getCellsContainingPoints() is recommended as it is
4337  *          faster.
4338  *  \param [in] pos - array of coordinates of the ball central point.
4339  *  \param [in] eps - ball radius.
4340  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4341  *         before inserting ids.
4342  *  \throw If the coordinates array is not set.
4343  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4344  *
4345  *  \if ENABLE_EXAMPLES
4346  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4347  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4348  *  \endif
4349  */
4350 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4351 {
4352   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4353   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4354   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4355 }
4356
4357 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4358                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4359                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4360 {
4361   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4362   if(spaceDim==3)
4363     {
4364       if(mDim==3)
4365         {
4366           const double *coords=_coords->getConstPointer();
4367           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4368         }
4369       else
4370         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4371     }
4372   else if(spaceDim==2)
4373     {
4374       if(mDim==2)
4375         {
4376           const double *coords=_coords->getConstPointer();
4377           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4378         }
4379       else
4380         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4381     }
4382   else if(spaceDim==1)
4383     {
4384       if(mDim==1)
4385         {
4386           const double *coords=_coords->getConstPointer();
4387           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4388         }
4389       else
4390         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4391     }
4392   else
4393     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4394 }
4395
4396 /*!
4397  * Finds cells in contact with several balls (i.e. points with precision).
4398  * This method is an extension of getCellContainingPoint() and
4399  * getCellsContainingPoint() for the case of multiple points.
4400  * 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.
4401  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4402  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4403  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4404  *         this->getSpaceDimension() * \a nbOfPoints
4405  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4406  *  \param [in] eps - radius of balls (i.e. the precision).
4407  *  \param [out] elts - vector returning ids of found cells.
4408  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4409  *         dividing cell ids in \a elts into groups each referring to one
4410  *         point. Its every element (except the last one) is an index pointing to the
4411  *         first id of a group of cells. For example cells in contact with the *i*-th
4412  *         point are described by following range of indices:
4413  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4414  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4415  *         Number of cells in contact with the *i*-th point is
4416  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4417  *  \throw If the coordinates array is not set.
4418  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4419  *
4420  *  \if ENABLE_EXAMPLES
4421  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4422  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4423  *  \endif
4424  */
4425 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4426                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4427 {
4428   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4429   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4430 }
4431
4432 /*!
4433  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4434  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4435  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4436  * 
4437  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4438  */
4439 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4440 {
4441   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4442   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4443 }
4444
4445 /*!
4446  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4447  * least two its edges intersect each other anywhere except their extremities. An
4448  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4449  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4450  *         cleared before filling in.
4451  *  \param [in] eps - precision.
4452  *  \throw If \a this->getMeshDimension() != 2.
4453  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4454  */
4455 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4456 {
4457   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4458   if(getMeshDimension()!=2)
4459     throw INTERP_KERNEL::Exception(msg);
4460   int spaceDim=getSpaceDimension();
4461   if(spaceDim!=2 && spaceDim!=3)
4462     throw INTERP_KERNEL::Exception(msg);
4463   const mcIdType *conn=_nodal_connec->getConstPointer();
4464   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4465   mcIdType nbOfCells=getNumberOfCells();
4466   std::vector<double> cell2DinS2;
4467   for(mcIdType i=0;i<nbOfCells;i++)
4468     {
4469       mcIdType offset=connI[i];
4470       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4471       if(nbOfNodesForCell<=3)
4472         continue;
4473       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4474       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4475       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4476         cells.push_back(i);
4477       cell2DinS2.clear();
4478     }
4479 }
4480
4481 /*!
4482  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4483  *
4484  * 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.
4485  * 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.
4486  *
4487  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4488  * This convex envelop is computed using Jarvis march algorithm.
4489  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4490  * 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)
4491  * 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.
4492  *
4493  * \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.
4494  * \sa MEDCouplingUMesh::colinearize2D
4495  */
4496 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4497 {
4498   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4499     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4500   checkFullyDefined();
4501   const double *coords=getCoords()->getConstPointer();
4502   mcIdType nbOfCells=getNumberOfCells();
4503   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4504   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4505   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4506   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4507   *workIndexOut=0;
4508   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4509   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4510   std::set<INTERP_KERNEL::NormalizedCellType> types;
4511   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4512   isChanged->alloc(0,1);
4513   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4514     {
4515       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4516       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4517         isChanged->pushBackSilent(i);
4518       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4519       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4520     }
4521   if(isChanged->empty())
4522     return 0;
4523   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4524   _types=types;
4525   return isChanged.retn();
4526 }
4527
4528 /*!
4529  * This method is \b NOT const because it can modify \a this.
4530  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4531  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4532  * \param policy specifies the type of extrusion chosen:
4533  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4534  *   will be repeated to build each level
4535  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4536  *   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
4537  *   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
4538  *   arc.
4539  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4540  */
4541 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4542 {
4543   checkFullyDefined();
4544   mesh1D->checkFullyDefined();
4545   if(!mesh1D->isContiguous1D())
4546     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4547   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4548     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4549   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4550     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4551   if(mesh1D->getMeshDimension()!=1)
4552     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4553   bool isQuad=false;
4554   if(isPresenceOfQuadratic())
4555     {
4556       if(mesh1D->isFullyQuadratic())
4557         isQuad=true;
4558       else
4559         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4560     }
4561   mcIdType oldNbOfNodes(getNumberOfNodes());
4562   MCAuto<DataArrayDouble> newCoords;
4563   switch(policy)
4564   {
4565     case 0:
4566       {
4567         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4568         break;
4569       }
4570     case 1:
4571       {
4572         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4573         break;
4574       }
4575     default:
4576       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4577   }
4578   setCoords(newCoords);
4579   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4580   updateTime();
4581   return ret.retn();
4582 }
4583
4584
4585 /*!
4586  * Checks if \a this mesh is constituted by only quadratic cells.
4587  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4588  *  \throw If the coordinates array is not set.
4589  *  \throw If the nodal connectivity of cells is not defined.
4590  */
4591 bool MEDCouplingUMesh::isFullyQuadratic() const
4592 {
4593   checkFullyDefined();
4594   bool ret=true;
4595   mcIdType nbOfCells=getNumberOfCells();
4596   for(mcIdType i=0;i<nbOfCells && ret;i++)
4597     {
4598       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4599       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4600       ret=cm.isQuadratic();
4601     }
4602   return ret;
4603 }
4604
4605 /*!
4606  * Checks if \a this mesh includes any quadratic cell.
4607  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4608  *  \throw If the coordinates array is not set.
4609  *  \throw If the nodal connectivity of cells is not defined.
4610  */
4611 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4612 {
4613   checkFullyDefined();
4614   bool ret=false;
4615   mcIdType nbOfCells=getNumberOfCells();
4616   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4617     {
4618       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4619       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4620       ret=cm.isQuadratic();
4621     }
4622   return ret;
4623 }
4624
4625 /*!
4626  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4627  * this mesh, it remains unchanged.
4628  *  \throw If the coordinates array is not set.
4629  *  \throw If the nodal connectivity of cells is not defined.
4630  */
4631 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4632 {
4633   checkFullyDefined();
4634   mcIdType nbOfCells=getNumberOfCells();
4635   mcIdType delta=0;
4636   const mcIdType *iciptr=_nodal_connec_index->begin();
4637   for(mcIdType i=0;i<nbOfCells;i++)
4638     {
4639       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4640       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4641       if(cm.isQuadratic())
4642         {
4643           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4644           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4645           if(!cml.isDynamic())
4646             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4647           else
4648             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4649         }
4650     }
4651   if(delta==0)
4652     return ;
4653   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4654   const mcIdType *icptr(_nodal_connec->begin());
4655   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4656   newConnI->alloc(nbOfCells+1,1);
4657   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4658   *ociptr=0;
4659   _types.clear();
4660   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4661     {
4662       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4663       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4664       if(!cm.isQuadratic())
4665         {
4666           _types.insert(type);
4667           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4668           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4669         }
4670       else
4671         {
4672           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4673           _types.insert(typel);
4674           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4675           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4676           if(cml.isDynamic())
4677             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4678           *ocptr++=ToIdType(typel);
4679           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4680           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4681         }
4682     }
4683   setConnectivity(newConn,newConnI,false);
4684 }
4685
4686 /*!
4687  * This method converts all linear cell in \a this to quadratic one.
4688  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4689  * 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)
4690  * 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.
4691  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4692  * end of the existing coordinates.
4693  *
4694  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4695  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4696  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4697  *
4698  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4699  *
4700  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4701  */
4702 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4703 {
4704   DataArrayIdType *conn=0,*connI=0;
4705   DataArrayDouble *coords=0;
4706   std::set<INTERP_KERNEL::NormalizedCellType> types;
4707   checkFullyDefined();
4708   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4709   MCAuto<DataArrayDouble> coordsSafe;
4710   int meshDim=getMeshDimension();
4711   switch(conversionType)
4712   {
4713     case 0:
4714       switch(meshDim)
4715       {
4716         case 1:
4717           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4718           connSafe=conn; connISafe=connI; coordsSafe=coords;
4719           break;
4720         case 2:
4721           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4722           connSafe=conn; connISafe=connI; coordsSafe=coords;
4723           break;
4724         case 3:
4725           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4726           connSafe=conn; connISafe=connI; coordsSafe=coords;
4727           break;
4728         default:
4729           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4730       }
4731       break;
4732         case 1:
4733           {
4734             switch(meshDim)
4735             {
4736               case 1:
4737                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4738                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4739                 break;
4740               case 2:
4741                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4742                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4743                 break;
4744               case 3:
4745                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4746                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4747                 break;
4748               default:
4749                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4750             }
4751             break;
4752           }
4753         default:
4754           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4755   }
4756   setConnectivity(connSafe,connISafe,false);
4757   _types=types;
4758   setCoords(coordsSafe);
4759   return ret.retn();
4760 }
4761
4762 /*!
4763  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4764  * so that the number of cells remains the same. Quadratic faces are converted to
4765  * polygons. This method works only for 2D meshes in
4766  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4767  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4768  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4769  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4770  *         a polylinized edge constituting the input polygon.
4771  *  \throw If the coordinates array is not set.
4772  *  \throw If the nodal connectivity of cells is not defined.
4773  *  \throw If \a this->getMeshDimension() != 2.
4774  *  \throw If \a this->getSpaceDimension() != 2.
4775  */
4776 void MEDCouplingUMesh::tessellate2D(double eps)
4777 {
4778   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4779   if(spaceDim!=2)
4780     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4781   switch(meshDim)
4782     {
4783     case 1:
4784       return tessellate2DCurveInternal(eps);
4785     case 2:
4786       return tessellate2DInternal(eps);
4787     default:
4788       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4789     }
4790 }
4791
4792 #if 0
4793 /*!
4794  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4795  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4796  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4797  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4798  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4799  * This method can be seen as the opposite method of colinearize2D.
4800  * 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
4801  * to avoid to modify the numbering of existing nodes.
4802  *
4803  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4804  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4805  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4806  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4807  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4808  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4809  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4810  *
4811  * \sa buildDescendingConnectivity2
4812  */
4813 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4814                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4815 {
4816   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4817     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4818   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4819   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4820     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4821   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4822     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4823   //DataArrayIdType *out0(0),*outi0(0);
4824   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4825   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4826   //out0s=out0s->buildUnique(); out0s->sort(true);
4827 }
4828 #endif
4829
4830
4831 /*!
4832  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4833  * In addition, returns an array mapping new cells to old ones. <br>
4834  * This method typically increases the number of cells in \a this mesh
4835  * but the number of nodes remains \b unchanged.
4836  * That's why the 3D splitting policies
4837  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4838  *  \param [in] policy - specifies a pattern used for splitting.
4839  * The semantic of \a policy is:
4840  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4841  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4842  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4843  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4844  *
4845  *
4846  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4847  *          an id of old cell producing it. The caller is to delete this array using
4848  *         decrRef() as it is no more needed.
4849  *
4850  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4851  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4852  *          and \a this->getMeshDimension() != 3.
4853  *  \throw If \a policy is not one of the four discussed above.
4854  *  \throw If the nodal connectivity of cells is not defined.
4855  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4856  */
4857 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4858 {
4859   switch(policy)
4860   {
4861     case 0:
4862       return simplexizePol0();
4863     case 1:
4864       return simplexizePol1();
4865     case INTERP_KERNEL::PLANAR_FACE_5:
4866         return simplexizePlanarFace5();
4867     case INTERP_KERNEL::PLANAR_FACE_6:
4868         return simplexizePlanarFace6();
4869     default:
4870       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)");
4871   }
4872 }
4873
4874 /*!
4875  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4876  * - 1D: INTERP_KERNEL::NORM_SEG2
4877  * - 2D: INTERP_KERNEL::NORM_TRI3
4878  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4879  *
4880  * This method is useful for users that need to use P1 field services as
4881  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4882  * All these methods need mesh support containing only simplex cells.
4883  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4884  *  \throw If the coordinates array is not set.
4885  *  \throw If the nodal connectivity of cells is not defined.
4886  *  \throw If \a this->getMeshDimension() < 1.
4887  */
4888 bool MEDCouplingUMesh::areOnlySimplexCells() const
4889 {
4890   checkFullyDefined();
4891   int mdim=getMeshDimension();
4892   if(mdim<1 || mdim>3)
4893     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4894   mcIdType nbCells=getNumberOfCells();
4895   const mcIdType *conn=_nodal_connec->begin();
4896   const mcIdType *connI=_nodal_connec_index->begin();
4897   for(mcIdType i=0;i<nbCells;i++)
4898     {
4899       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4900       if(!cm.isSimplex())
4901         return false;
4902     }
4903   return true;
4904 }
4905
4906
4907
4908 /*!
4909  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4910  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4911  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4912  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4913  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4914  * so it can be useful to call mergeNodes() before calling this method.
4915  *  \throw If \a this->getMeshDimension() <= 1.
4916  *  \throw If the coordinates array is not set.
4917  *  \throw If the nodal connectivity of cells is not defined.
4918  */
4919 void MEDCouplingUMesh::convertDegeneratedCells()
4920 {
4921   checkFullyDefined();
4922   if(getMeshDimension()<=1)
4923     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4924   mcIdType nbOfCells=getNumberOfCells();
4925   if(nbOfCells<1)
4926     return ;
4927   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4928   mcIdType *conn=_nodal_connec->getPointer();
4929   mcIdType *index=_nodal_connec_index->getPointer();
4930   mcIdType posOfCurCell=0;
4931   mcIdType newPos=0;
4932   mcIdType lgthOfCurCell;
4933   for(mcIdType i=0;i<nbOfCells;i++)
4934     {
4935       lgthOfCurCell=index[i+1]-posOfCurCell;
4936       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4937       mcIdType newLgth;
4938       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4939                                                                                                      conn+newPos+1,newLgth);
4940       conn[newPos]=newType;
4941       newPos+=newLgth+1;
4942       posOfCurCell=index[i+1];
4943       index[i+1]=newPos;
4944     }
4945   if(newPos!=initMeshLgth)
4946     _nodal_connec->reAlloc(newPos);
4947   computeTypes();
4948 }
4949
4950 /*!
4951  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4952  * A cell is flat in the following cases:
4953  *   - for a linear cell, all points in the connectivity are equal
4954  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4955  *   identical quadratic points
4956  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4957  *      this array using decrRef() as it is no more needed.
4958  */
4959 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4960 {
4961   checkFullyDefined();
4962   if(getMeshDimension()<=1)
4963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4964   mcIdType nbOfCells=getNumberOfCells();
4965   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4966   if(nbOfCells<1)
4967     return ret.retn();
4968   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4969   mcIdType *conn=_nodal_connec->getPointer();
4970   mcIdType *index=_nodal_connec_index->getPointer();
4971   mcIdType posOfCurCell=0;
4972   mcIdType newPos=0;
4973   mcIdType lgthOfCurCell, nbDelCells(0);
4974   for(mcIdType i=0;i<nbOfCells;i++)
4975     {
4976       lgthOfCurCell=index[i+1]-posOfCurCell;
4977       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4978       mcIdType newLgth;
4979       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4980                                                                                                      conn+newPos+1,newLgth);
4981       // Shall we delete the cell if it is completely degenerated:
4982       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4983       if (delCell)
4984         {
4985           nbDelCells++;
4986           ret->pushBackSilent(i);
4987         }
4988       else   //if the cell is to be deleted, simply stay at the same place
4989         {
4990           conn[newPos]=newType;
4991           newPos+=newLgth+1;
4992         }
4993       posOfCurCell=index[i+1];
4994       index[i+1-nbDelCells]=newPos;
4995     }
4996   if(newPos!=initMeshLgth)
4997     _nodal_connec->reAlloc(newPos);
4998   const mcIdType nCellDel=ret->getNumberOfTuples();
4999   if (nCellDel)
5000     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
5001   computeTypes();
5002   return ret.retn();
5003 }
5004
5005 /*!
5006  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
5007  * Only connectivity is considered here.
5008  */
5009 bool MEDCouplingUMesh::removeDegenerated1DCells()
5010 {
5011   checkConnectivityFullyDefined();
5012   if(getMeshDimension()!=1)
5013     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
5014   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
5015   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
5016   {
5017     for(std::size_t i=0;i<nbCells;i++)
5018       {
5019         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5020         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5021           {
5022             if(conn[conni[i]+1]!=conn[conni[i]+2])
5023               {
5024                 newSize++;
5025                 newSize2+=conni[i+1]-conni[i];
5026               }
5027           }
5028         else
5029           {
5030             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5031             throw INTERP_KERNEL::Exception(oss.str());
5032           }
5033       }
5034   }
5035   if(newSize==nbCells)//no cells has been removed -> do nothing
5036     return false;
5037   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5038   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5039   for(std::size_t i=0;i<nbCells;i++)
5040     {
5041       if(conn[conni[i]+1]!=conn[conni[i]+2])
5042         {
5043           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5044           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5045           newConnIPtr++;
5046         }
5047     }
5048   setConnectivity(newConn,newConnI,true);
5049   return true;
5050 }
5051
5052 /*!
5053  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5054  * A cell is considered to be oriented correctly if an angle between its
5055  * normal vector and a given vector is less than \c PI / \c 2.
5056  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5057  *         cells.
5058  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5059  *         checked.
5060  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5061  *         is not cleared before filling in.
5062  *  \throw If \a this->getMeshDimension() != 2.
5063  *  \throw If \a this->getSpaceDimension() != 3.
5064  *
5065  *  \if ENABLE_EXAMPLES
5066  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5067  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5068  *  \endif
5069  */
5070 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5071 {
5072   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5073     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5074   mcIdType nbOfCells=getNumberOfCells();
5075   const mcIdType *conn=_nodal_connec->begin();
5076   const mcIdType *connI=_nodal_connec_index->begin();
5077   const double *coordsPtr=_coords->begin();
5078   for(mcIdType i=0;i<nbOfCells;i++)
5079     {
5080       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5081       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5082         {
5083           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5084           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5085             cells.push_back(i);
5086         }
5087     }
5088 }
5089
5090 /*!
5091  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5092  * considered to be oriented correctly if an angle between its normal vector and a
5093  * given vector is less than \c PI / \c 2.
5094  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5095  *         cells.
5096  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5097  *         checked.
5098  *  \throw If \a this->getMeshDimension() != 2.
5099  *  \throw If \a this->getSpaceDimension() != 3.
5100  *
5101  *  \if ENABLE_EXAMPLES
5102  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5103  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5104  *  \endif
5105  *
5106  *  \sa changeOrientationOfCells
5107  */
5108 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5109 {
5110   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5111     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5112   mcIdType nbOfCells=getNumberOfCells();
5113   mcIdType *conn(_nodal_connec->getPointer());
5114   const mcIdType *connI(_nodal_connec_index->begin());
5115   const double *coordsPtr(_coords->begin());
5116   bool isModified(false);
5117   for(mcIdType i=0;i<nbOfCells;i++)
5118     {
5119       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5120       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5121         {
5122           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5123           bool isQuadratic(cm.isQuadratic());
5124           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5125             {
5126               isModified=true;
5127               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5128             }
5129         }
5130     }
5131   if(isModified)
5132     _nodal_connec->declareAsNew();
5133   updateTime();
5134 }
5135
5136 /*!
5137  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5138  *
5139  * \sa orientCorrectly2DCells
5140  */
5141 void MEDCouplingUMesh::changeOrientationOfCells()
5142 {
5143   int mdim(getMeshDimension());
5144   if(mdim!=2 && mdim!=1)
5145     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5146   mcIdType nbOfCells=getNumberOfCells();
5147   mcIdType *conn(_nodal_connec->getPointer());
5148   const mcIdType *connI(_nodal_connec_index->begin());
5149   if(mdim==2)
5150     {//2D
5151       for(mcIdType i=0;i<nbOfCells;i++)
5152         {
5153           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5154           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5155           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5156         }
5157     }
5158   else
5159     {//1D
5160       for(mcIdType i=0;i<nbOfCells;i++)
5161         {
5162           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5163           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5164           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5165         }
5166     }
5167 }
5168
5169 /*!
5170  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5171  * oriented facets. The normal vector of the facet should point out of the cell.
5172  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5173  *         is not cleared before filling in.
5174  *  \throw If \a this->getMeshDimension() != 3.
5175  *  \throw If \a this->getSpaceDimension() != 3.
5176  *  \throw If the coordinates array is not set.
5177  *  \throw If the nodal connectivity of cells is not defined.
5178  *
5179  *  \if ENABLE_EXAMPLES
5180  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5181  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5182  *  \endif
5183  */
5184 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5185 {
5186   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5187     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5188   mcIdType nbOfCells=getNumberOfCells();
5189   const mcIdType *conn=_nodal_connec->begin();
5190   const mcIdType *connI=_nodal_connec_index->begin();
5191   const double *coordsPtr=_coords->begin();
5192   for(mcIdType i=0;i<nbOfCells;i++)
5193     {
5194       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5195       if(type==INTERP_KERNEL::NORM_POLYHED)
5196         {
5197           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5198             cells.push_back(i);
5199         }
5200     }
5201 }
5202
5203 /*!
5204  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5205  * out of the cell.
5206  *  \throw If \a this->getMeshDimension() != 3.
5207  *  \throw If \a this->getSpaceDimension() != 3.
5208  *  \throw If the coordinates array is not set.
5209  *  \throw If the nodal connectivity of cells is not defined.
5210  *  \throw If the reparation fails.
5211  *
5212  *  \if ENABLE_EXAMPLES
5213  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5214  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5215  *  \endif
5216  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5217  */
5218 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5219 {
5220   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5221     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5222   mcIdType nbOfCells=getNumberOfCells();
5223   mcIdType *conn=_nodal_connec->getPointer();
5224   const mcIdType *connI=_nodal_connec_index->begin();
5225   const double *coordsPtr=_coords->begin();
5226   for(mcIdType i=0;i<nbOfCells;i++)
5227     {
5228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5229       if(type==INTERP_KERNEL::NORM_POLYHED)
5230         {
5231           try
5232           {
5233               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5234                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5235           }
5236           catch(INTERP_KERNEL::Exception& e)
5237           {
5238               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5239               throw INTERP_KERNEL::Exception(oss.str());
5240           }
5241         }
5242     }
5243   updateTime();
5244 }
5245
5246 /*!
5247  * This method invert orientation of all cells in \a this.
5248  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5249  * This method only operates on the connectivity so coordinates are not touched at all.
5250  */
5251 void MEDCouplingUMesh::invertOrientationOfAllCells()
5252 {
5253   checkConnectivityFullyDefined();
5254   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5255   mcIdType *conn(_nodal_connec->getPointer());
5256   const mcIdType *conni(_nodal_connec_index->begin());
5257   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5258     {
5259       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5260       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5261       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5262         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5263     }
5264   updateTime();
5265 }
5266
5267 /*!
5268  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5269  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5270  * according to which the first facet of the cell should be oriented to have the normal vector
5271  * pointing out of cell.
5272  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5273  *         cells. The caller is to delete this array using decrRef() as it is no more
5274  *         needed.
5275  *  \throw If \a this->getMeshDimension() != 3.
5276  *  \throw If \a this->getSpaceDimension() != 3.
5277  *  \throw If the coordinates array is not set.
5278  *  \throw If the nodal connectivity of cells is not defined.
5279  *
5280  *  \if ENABLE_EXAMPLES
5281  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5282  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5283  *  \endif
5284  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5285  */
5286 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5287 {
5288   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5289   if(getMeshDimension()!=3)
5290     throw INTERP_KERNEL::Exception(msg);
5291   int spaceDim=getSpaceDimension();
5292   if(spaceDim!=3)
5293     throw INTERP_KERNEL::Exception(msg);
5294   //
5295   mcIdType nbOfCells=getNumberOfCells();
5296   mcIdType *conn=_nodal_connec->getPointer();
5297   const mcIdType *connI=_nodal_connec_index->begin();
5298   const double *coo=getCoords()->begin();
5299   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5300   for(mcIdType i=0;i<nbOfCells;i++)
5301     {
5302       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5303       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5304         {
5305           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5306             {
5307               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5308               cells->pushBackSilent(i);
5309             }
5310         }
5311     }
5312   return cells.retn();
5313 }
5314
5315 /*!
5316  * This method is a faster method to correct orientation of all 3D cells in \a this.
5317  * 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.
5318  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5319  *
5320  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5321  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5322  */
5323 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5324 {
5325   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5326     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5327   mcIdType nbOfCells=getNumberOfCells();
5328   mcIdType *conn=_nodal_connec->getPointer();
5329   const mcIdType *connI=_nodal_connec_index->begin();
5330   const double *coordsPtr=_coords->begin();
5331   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5332   for(mcIdType i=0;i<nbOfCells;i++)
5333     {
5334       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5335       switch(type)
5336       {
5337         case INTERP_KERNEL::NORM_TETRA4:
5338           {
5339             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5340               {
5341                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5342                 ret->pushBackSilent(i);
5343               }
5344             break;
5345           }
5346         case INTERP_KERNEL::NORM_PYRA5:
5347           {
5348             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5349               {
5350                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5351                 ret->pushBackSilent(i);
5352               }
5353             break;
5354           }
5355         case INTERP_KERNEL::NORM_PENTA6:
5356         case INTERP_KERNEL::NORM_HEXA8:
5357         case INTERP_KERNEL::NORM_HEXGP12:
5358           {
5359             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5360               {
5361                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5362                 ret->pushBackSilent(i);
5363               }
5364             break;
5365           }
5366         case INTERP_KERNEL::NORM_POLYHED:
5367           {
5368             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5369               {
5370                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5371                 ret->pushBackSilent(i);
5372               }
5373             break;
5374           }
5375         default:
5376           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 !");
5377       }
5378     }
5379   updateTime();
5380   return ret.retn();
5381 }
5382
5383 /*!
5384  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5385  * If it is not the case an exception will be thrown.
5386  * This method is fast because the first cell of \a this is used to compute the plane.
5387  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5388  * \param pos output of size at least 3 used to store a point owned of searched plane.
5389  */
5390 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5391 {
5392   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5393     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5394   const mcIdType *conn=_nodal_connec->begin();
5395   const mcIdType *connI=_nodal_connec_index->begin();
5396   const double *coordsPtr=_coords->begin();
5397   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5398   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5399 }
5400
5401 /*!
5402  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5403  * cells. Currently cells of the following types are treated:
5404  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5405  * For a cell of other type an exception is thrown.
5406  * Space dimension of a 2D mesh can be either 2 or 3.
5407  * The Edge Ratio of a cell \f$t\f$ is:
5408  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5409  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5410  *  the smallest edge lengths of \f$t\f$.
5411  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5412  *          cells and one time, lying on \a this mesh. The caller is to delete this
5413  *          field using decrRef() as it is no more needed.
5414  *  \throw If the coordinates array is not set.
5415  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5416  *  \throw If the connectivity data array has more than one component.
5417  *  \throw If the connectivity data array has a named component.
5418  *  \throw If the connectivity index data array has more than one component.
5419  *  \throw If the connectivity index data array has a named component.
5420  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5421  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5422  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5423  */
5424 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5425 {
5426   checkConsistencyLight();
5427   int spaceDim=getSpaceDimension();
5428   int meshDim=getMeshDimension();
5429   if(spaceDim!=2 && spaceDim!=3)
5430     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5431   if(meshDim!=2 && meshDim!=3)
5432     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5433   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5434   ret->setMesh(this);
5435   mcIdType nbOfCells=getNumberOfCells();
5436   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5437   arr->alloc(nbOfCells,1);
5438   double *pt=arr->getPointer();
5439   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5440   const mcIdType *conn=_nodal_connec->begin();
5441   const mcIdType *connI=_nodal_connec_index->begin();
5442   const double *coo=_coords->begin();
5443   double tmp[12];
5444   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5445     {
5446       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5447       switch(t)
5448       {
5449         case INTERP_KERNEL::NORM_TRI3:
5450           {
5451             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5452             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5453             break;
5454           }
5455         case INTERP_KERNEL::NORM_QUAD4:
5456           {
5457             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5458             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5459             break;
5460           }
5461         case INTERP_KERNEL::NORM_TETRA4:
5462           {
5463             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5464             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5465             break;
5466           }
5467         default:
5468           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5469       }
5470       conn+=connI[i+1]-connI[i];
5471     }
5472   ret->setName("EdgeRatio");
5473   ret->synchronizeTimeWithSupport();
5474   return ret.retn();
5475 }
5476
5477 /*!
5478  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5479  * cells. Currently cells of the following types are treated:
5480  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5481  * For a cell of other type an exception is thrown.
5482  * Space dimension of a 2D mesh can be either 2 or 3.
5483  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5484  *          cells and one time, lying on \a this mesh. The caller is to delete this
5485  *          field using decrRef() as it is no more needed.
5486  *  \throw If the coordinates array is not set.
5487  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5488  *  \throw If the connectivity data array has more than one component.
5489  *  \throw If the connectivity data array has a named component.
5490  *  \throw If the connectivity index data array has more than one component.
5491  *  \throw If the connectivity index data array has a named component.
5492  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5493  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5494  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5495  */
5496 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5497 {
5498   checkConsistencyLight();
5499   int spaceDim=getSpaceDimension();
5500   int meshDim=getMeshDimension();
5501   if(spaceDim!=2 && spaceDim!=3)
5502     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5503   if(meshDim!=2 && meshDim!=3)
5504     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5505   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5506   ret->setMesh(this);
5507   mcIdType nbOfCells=getNumberOfCells();
5508   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5509   arr->alloc(nbOfCells,1);
5510   double *pt=arr->getPointer();
5511   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5512   const mcIdType *conn=_nodal_connec->begin();
5513   const mcIdType *connI=_nodal_connec_index->begin();
5514   const double *coo=_coords->begin();
5515   double tmp[12];
5516   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5517     {
5518       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5519       switch(t)
5520       {
5521         case INTERP_KERNEL::NORM_TRI3:
5522           {
5523             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5524             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5525             break;
5526           }
5527         case INTERP_KERNEL::NORM_QUAD4:
5528           {
5529             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5530             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5531             break;
5532           }
5533         case INTERP_KERNEL::NORM_TETRA4:
5534           {
5535             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5536             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5537             break;
5538           }
5539         default:
5540           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5541       }
5542       conn+=connI[i+1]-connI[i];
5543     }
5544   ret->setName("AspectRatio");
5545   ret->synchronizeTimeWithSupport();
5546   return ret.retn();
5547 }
5548
5549 /*!
5550  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5551  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5552  * in 3D space. Currently only cells of the following types are
5553  * treated: INTERP_KERNEL::NORM_QUAD4.
5554  * For a cell of other type an exception is thrown.
5555  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5556  * Defining
5557  * \f$t=\vec{da}\times\vec{ab}\f$,
5558  * \f$u=\vec{ab}\times\vec{bc}\f$
5559  * \f$v=\vec{bc}\times\vec{cd}\f$
5560  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5561  *  \f[
5562  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5563  *  \f]
5564  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5565  *          cells and one time, lying on \a this mesh. The caller is to delete this
5566  *          field using decrRef() as it is no more needed.
5567  *  \throw If the coordinates array is not set.
5568  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5569  *  \throw If the connectivity data array has more than one component.
5570  *  \throw If the connectivity data array has a named component.
5571  *  \throw If the connectivity index data array has more than one component.
5572  *  \throw If the connectivity index data array has a named component.
5573  *  \throw If \a this->getMeshDimension() != 2.
5574  *  \throw If \a this->getSpaceDimension() != 3.
5575  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5576  */
5577 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5578 {
5579   checkConsistencyLight();
5580   int spaceDim=getSpaceDimension();
5581   int meshDim=getMeshDimension();
5582   if(spaceDim!=3)
5583     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5584   if(meshDim!=2)
5585     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5586   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5587   ret->setMesh(this);
5588   mcIdType nbOfCells=getNumberOfCells();
5589   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5590   arr->alloc(nbOfCells,1);
5591   double *pt=arr->getPointer();
5592   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5593   const mcIdType *conn=_nodal_connec->begin();
5594   const mcIdType *connI=_nodal_connec_index->begin();
5595   const double *coo=_coords->begin();
5596   double tmp[12];
5597   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5598     {
5599       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5600       switch(t)
5601       {
5602         case INTERP_KERNEL::NORM_QUAD4:
5603           {
5604             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5605             *pt=INTERP_KERNEL::quadWarp(tmp);
5606             break;
5607           }
5608         default:
5609           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5610       }
5611       conn+=connI[i+1]-connI[i];
5612     }
5613   ret->setName("Warp");
5614   ret->synchronizeTimeWithSupport();
5615   return ret.retn();
5616 }
5617
5618
5619 /*!
5620  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5621  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5622  * treated: INTERP_KERNEL::NORM_QUAD4.
5623  * The skew is computed as follow for a quad with points (a,b,c,d): let
5624  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5625  * then the skew is computed as:
5626  *  \f[
5627  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5628  *  \f]
5629  *
5630  * For a cell of other type an exception is thrown.
5631  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5632  *          cells and one time, lying on \a this mesh. The caller is to delete this
5633  *          field using decrRef() as it is no more needed.
5634  *  \throw If the coordinates array is not set.
5635  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5636  *  \throw If the connectivity data array has more than one component.
5637  *  \throw If the connectivity data array has a named component.
5638  *  \throw If the connectivity index data array has more than one component.
5639  *  \throw If the connectivity index data array has a named component.
5640  *  \throw If \a this->getMeshDimension() != 2.
5641  *  \throw If \a this->getSpaceDimension() != 3.
5642  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5643  */
5644 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5645 {
5646   checkConsistencyLight();
5647   int spaceDim=getSpaceDimension();
5648   int meshDim=getMeshDimension();
5649   if(spaceDim!=3)
5650     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5651   if(meshDim!=2)
5652     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5653   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5654   ret->setMesh(this);
5655   mcIdType nbOfCells=getNumberOfCells();
5656   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5657   arr->alloc(nbOfCells,1);
5658   double *pt=arr->getPointer();
5659   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5660   const mcIdType *conn=_nodal_connec->begin();
5661   const mcIdType *connI=_nodal_connec_index->begin();
5662   const double *coo=_coords->begin();
5663   double tmp[12];
5664   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5665     {
5666       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5667       switch(t)
5668       {
5669         case INTERP_KERNEL::NORM_QUAD4:
5670           {
5671             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5672             *pt=INTERP_KERNEL::quadSkew(tmp);
5673             break;
5674           }
5675         default:
5676           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5677       }
5678       conn+=connI[i+1]-connI[i];
5679     }
5680   ret->setName("Skew");
5681   ret->synchronizeTimeWithSupport();
5682   return ret.retn();
5683 }
5684
5685 /*!
5686  * 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.
5687  *
5688  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5689  *
5690  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5691  */
5692 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5693 {
5694   checkConsistencyLight();
5695   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5696   ret->setMesh(this);
5697   std::set<INTERP_KERNEL::NormalizedCellType> types;
5698   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5699   int spaceDim(getSpaceDimension());
5700   mcIdType nbCells(getNumberOfCells());
5701   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5702   arr->alloc(nbCells,1);
5703   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5704     {
5705       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5706       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5707       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5708     }
5709   ret->setArray(arr);
5710   ret->setName("Diameter");
5711   return ret.retn();
5712 }
5713
5714 /*!
5715  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5716  *
5717  * \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)
5718  *                         For all other cases this input parameter is ignored.
5719  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5720  *
5721  * \throw If \a this is not fully set (coordinates and connectivity).
5722  * \throw If a cell in \a this has no valid nodeId.
5723  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5724  */
5725 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5726 {
5727   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5728   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.
5729     return getBoundingBoxForBBTreeFast();
5730   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5731     {
5732       bool presenceOfQuadratic(false);
5733       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5734         {
5735           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5736           if(cm.isQuadratic())
5737             presenceOfQuadratic=true;
5738         }
5739       if(!presenceOfQuadratic)
5740         return getBoundingBoxForBBTreeFast();
5741       if(mDim==2 && sDim==2)
5742         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5743       else
5744         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5745     }
5746   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) !");
5747 }
5748
5749 /*!
5750  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5751  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5752  *
5753  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5754  *
5755  * \throw If \a this is not fully set (coordinates and connectivity).
5756  * \throw If a cell in \a this has no valid nodeId.
5757  */
5758 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5759 {
5760   checkFullyDefined();
5761   int spaceDim(getSpaceDimension());
5762   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5763   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5764   double *bbox(ret->getPointer());
5765   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5766     {
5767       bbox[2*i]=std::numeric_limits<double>::max();
5768       bbox[2*i+1]=-std::numeric_limits<double>::max();
5769     }
5770   const double *coordsPtr(_coords->begin());
5771   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5772   for(mcIdType i=0;i<nbOfCells;i++)
5773     {
5774       mcIdType offset=connI[i]+1;
5775       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5776       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5777         {
5778           mcIdType nodeId=conn[offset+j];
5779           if(nodeId>=0 && nodeId<nbOfNodes)
5780             {
5781               for(int k=0;k<spaceDim;k++)
5782                 {
5783                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5784                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5785                 }
5786               kk++;
5787             }
5788         }
5789       if(kk==0)
5790         {
5791           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5792           throw INTERP_KERNEL::Exception(oss.str());
5793         }
5794     }
5795   return ret.retn();
5796 }
5797
5798 /*!
5799  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5800  * useful for 2D meshes having quadratic cells
5801  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5802  * the two extremities of the arc of circle).
5803  *
5804  * \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)
5805  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5806  * \throw If \a this is not fully defined.
5807  * \throw If \a this is not a mesh with meshDimension equal to 2.
5808  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5809  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5810  */
5811 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5812 {
5813   checkFullyDefined();
5814   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5815
5816   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5817   mcIdType nbOfCells=getNumberOfCells();
5818   if(spaceDim!=2 || mDim!=2)
5819     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!");
5820   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5821   double *bbox(ret->getPointer());
5822   const double *coords(_coords->begin());
5823   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5824   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5825     {
5826       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5827       mcIdType sz(connI[1]-connI[0]-1);
5828       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5829       INTERP_KERNEL::QuadraticPolygon *pol(0);
5830       for(mcIdType j=0;j<sz;j++)
5831         {
5832           mcIdType nodeId(conn[*connI+1+j]);
5833           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5834         }
5835       if(!cm.isQuadratic())
5836         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5837       else
5838         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5839       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5840       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5841     }
5842   return ret.retn();
5843 }
5844
5845 /*!
5846  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5847  * useful for 2D meshes having quadratic cells
5848  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5849  * the two extremities of the arc of circle).
5850  *
5851  * \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)
5852  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5853  * \throw If \a this is not fully defined.
5854  * \throw If \a this is not a mesh with meshDimension equal to 1.
5855  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5856  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5857  */
5858 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5859 {
5860   checkFullyDefined();
5861   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5862   mcIdType nbOfCells=getNumberOfCells();
5863   if(spaceDim!=2 || mDim!=1)
5864     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!");
5865   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5866   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5867   double *bbox(ret->getPointer());
5868   const double *coords(_coords->begin());
5869   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5870   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5871     {
5872       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5873       mcIdType sz(connI[1]-connI[0]-1);
5874       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5875       INTERP_KERNEL::Edge *edge(0);
5876       for(mcIdType j=0;j<sz;j++)
5877         {
5878           mcIdType nodeId(conn[*connI+1+j]);
5879           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5880         }
5881       if(!cm.isQuadratic())
5882         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5883       else
5884         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5885       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5886       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5887     }
5888   return ret.retn();
5889 }
5890
5891 /// @cond INTERNAL
5892
5893 namespace MEDCouplingImpl
5894 {
5895   class ConnReader
5896   {
5897   public:
5898     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5899     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5900   private:
5901     const mcIdType *_conn;
5902     mcIdType _val;
5903   };
5904
5905   class ConnReader2
5906   {
5907   public:
5908     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5909     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5910   private:
5911     const mcIdType *_conn;
5912     mcIdType _val;
5913   };
5914 }
5915
5916 /// @endcond
5917
5918 /*!
5919  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5920  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5921  * \a this is composed in cell types.
5922  * The returned array is of size 3*n where n is the number of different types present in \a this.
5923  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5924  * This parameter is kept only for compatibility with other method listed above.
5925  */
5926 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5927 {
5928   checkConnectivityFullyDefined();
5929   const mcIdType *conn=_nodal_connec->begin();
5930   const mcIdType *connI=_nodal_connec_index->begin();
5931   const mcIdType *work=connI;
5932   mcIdType nbOfCells=getNumberOfCells();
5933   std::size_t n=getAllGeoTypes().size();
5934   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5935   std::set<INTERP_KERNEL::NormalizedCellType> types;
5936   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5937     {
5938       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5939       if(types.find(typ)!=types.end())
5940         {
5941           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5942           oss << " is not contiguous !";
5943           throw INTERP_KERNEL::Exception(oss.str());
5944         }
5945       types.insert(typ);
5946       ret[3*i]=typ;
5947       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5948       ret[3*i+1]=ToIdType(std::distance(work,work2));
5949       work=work2;
5950     }
5951   return ret;
5952 }
5953
5954 /*!
5955  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5956  * only for types cell, type node is not managed.
5957  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5958  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5959  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5960  * If 2 or more same geometric type is in \a code and exception is thrown too.
5961  *
5962  * This method firstly checks
5963  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5964  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5965  * an exception is thrown too.
5966  *
5967  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5968  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5969  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5970  */
5971 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5972 {
5973   if(code.empty())
5974     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5975   std::size_t sz=code.size();
5976   std::size_t n=sz/3;
5977   if(sz%3!=0)
5978     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5979   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5980   mcIdType nb=0;
5981   bool isNoPflUsed=true;
5982   for(std::size_t i=0;i<n;i++)
5983     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5984       {
5985         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5986         nb+=code[3*i+1];
5987         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5988           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5989         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5990       }
5991   if(types.size()!=n)
5992     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5993   if(isNoPflUsed)
5994     {
5995       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5996         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5997       if(types.size()==_types.size())
5998         return 0;
5999     }
6000   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
6001   ret->alloc(nb,1);
6002   mcIdType *retPtr=ret->getPointer();
6003   const mcIdType *connI=_nodal_connec_index->begin();
6004   const mcIdType *conn=_nodal_connec->begin();
6005   mcIdType nbOfCells=getNumberOfCells();
6006   const mcIdType *i=connI;
6007   int kk=0;
6008   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6009     {
6010       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
6011       mcIdType offset=ToIdType(std::distance(connI,i));
6012       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
6013       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
6014       if(code[3*kk+2]==-1)
6015         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
6016           *retPtr++=k+offset;
6017       else
6018         {
6019           mcIdType idInIdsPerType=code[3*kk+2];
6020           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6021             {
6022               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6023               if(zePfl)
6024                 {
6025                   zePfl->checkAllocated();
6026                   if(zePfl->getNumberOfComponents()==1)
6027                     {
6028                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6029                         {
6030                           if(*k>=0 && *k<nbOfCellsOfCurType)
6031                             *retPtr=(*k)+offset;
6032                           else
6033                             {
6034                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6035                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6036                               throw INTERP_KERNEL::Exception(oss.str());
6037                             }
6038                         }
6039                     }
6040                   else
6041                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6042                 }
6043               else
6044                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6045             }
6046           else
6047             {
6048               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6049               oss << " should be in [0," << idsPerType.size() << ") !";
6050               throw INTERP_KERNEL::Exception(oss.str());
6051             }
6052         }
6053       i=j;
6054     }
6055   return ret.retn();
6056 }
6057
6058 /*!
6059  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6060  * 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.
6061  * 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.
6062  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6063  *
6064  * \param [in] profile list of IDs constituing the profile
6065  * \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.
6066  * \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,
6067  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6068  * \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.
6069  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6070  * \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
6071  */
6072 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6073 {
6074   if(!profile)
6075     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6076   if(profile->getNumberOfComponents()!=1)
6077     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6078   checkConnectivityFullyDefined();
6079   const mcIdType *conn=_nodal_connec->begin();
6080   const mcIdType *connI=_nodal_connec_index->begin();
6081   mcIdType nbOfCells=getNumberOfCells();
6082   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6083   std::vector<mcIdType> typeRangeVals(1);
6084   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6085     {
6086       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6087       if(std::find(types.begin(),types.end(),curType)!=types.end())
6088         {
6089           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6090         }
6091       types.push_back(curType);
6092       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6093       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6094     }
6095   //
6096   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6097   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6098   MCAuto<DataArrayIdType> tmp0=castArr;
6099   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6100   MCAuto<DataArrayIdType> tmp2=castsPresent;
6101   //
6102   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6103   code.resize(3*nbOfCastsFinal);
6104   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6105   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6106   for(mcIdType i=0;i<nbOfCastsFinal;i++)
6107     {
6108       mcIdType castId=castsPresent->getIJ(i,0);
6109       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6110       idsInPflPerType2.push_back(tmp3);
6111       code[3*i]=ToIdType(types[castId]);
6112       code[3*i+1]=tmp3->getNumberOfTuples();
6113       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6114       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6115         {
6116           tmp4->copyStringInfoFrom(*profile);
6117           idsPerType2.push_back(tmp4);
6118           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6119         }
6120       else
6121         {
6122           code[3*i+2]=-1;
6123         }
6124     }
6125   std::size_t sz2=idsInPflPerType2.size();
6126   idsInPflPerType.resize(sz2);
6127   for(std::size_t i=0;i<sz2;i++)
6128     {
6129       DataArrayIdType *locDa=idsInPflPerType2[i];
6130       locDa->incrRef();
6131       idsInPflPerType[i]=locDa;
6132     }
6133   std::size_t sz=idsPerType2.size();
6134   idsPerType.resize(sz);
6135   for(std::size_t i=0;i<sz;i++)
6136     {
6137       DataArrayIdType *locDa=idsPerType2[i];
6138       locDa->incrRef();
6139       idsPerType[i]=locDa;
6140     }
6141 }
6142
6143 /*!
6144  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6145  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6146  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6147  * 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.
6148  */
6149 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6150 {
6151   checkFullyDefined();
6152   nM1LevMesh->checkFullyDefined();
6153   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6154     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6155   if(_coords!=nM1LevMesh->getCoords())
6156     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6157   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6158   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6159   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6160   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6161   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6162   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6163   tmp->setConnectivity(tmp0,tmp1);
6164   tmp->renumberCells(ret0->begin(),false);
6165   revDesc=tmp->getNodalConnectivity();
6166   revDescIndx=tmp->getNodalConnectivityIndex();
6167   DataArrayIdType *ret=0;
6168   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6169     {
6170       mcIdType tmp2;
6171       ret->getMaxValue(tmp2);
6172       ret->decrRef();
6173       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6174       throw INTERP_KERNEL::Exception(oss.str());
6175     }
6176   nM1LevMeshIds=ret;
6177   //
6178   revDesc->incrRef();
6179   revDescIndx->incrRef();
6180   ret1->incrRef();
6181   ret0->incrRef();
6182   meshnM1Old2New=ret0;
6183   return ret1;
6184 }
6185
6186 /*!
6187  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6188  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6189  * in "Old to New" mode.
6190  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6191  *          this array using decrRef() as it is no more needed.
6192  *  \throw If the nodal connectivity of cells is not defined.
6193  */
6194 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6195 {
6196   checkConnectivityFullyDefined();
6197   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6198   renumberCells(ret->begin(),false);
6199   return ret.retn();
6200 }
6201
6202 /*!
6203  * This methods checks that cells are sorted by their types.
6204  * This method makes asumption (no check) that connectivity is correctly set before calling.
6205  */
6206 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6207 {
6208   checkFullyDefined();
6209   const mcIdType *conn=_nodal_connec->begin();
6210   const mcIdType *connI=_nodal_connec_index->begin();
6211   mcIdType nbOfCells=getNumberOfCells();
6212   std::set<INTERP_KERNEL::NormalizedCellType> types;
6213   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6214     {
6215       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6216       if(types.find(curType)!=types.end())
6217         return false;
6218       types.insert(curType);
6219       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6220     }
6221   return true;
6222 }
6223
6224 /*!
6225  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6226  * The geometric type order is specified by MED file.
6227  *
6228  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6229  */
6230 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6231 {
6232   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6233 }
6234
6235 /*!
6236  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6237  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6238  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6239  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6240  */
6241 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6242 {
6243   checkFullyDefined();
6244   const mcIdType *conn=_nodal_connec->begin();
6245   const mcIdType *connI=_nodal_connec_index->begin();
6246   mcIdType nbOfCells=getNumberOfCells();
6247   if(nbOfCells==0)
6248     return true;
6249   mcIdType lastPos=-1;
6250   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6251   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6252     {
6253       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6254       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6255       if(isTypeExists!=orderEnd)
6256         {
6257           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6258           if(pos<=lastPos)
6259             return false;
6260           lastPos=pos;
6261           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6262         }
6263       else
6264         {
6265           if(sg.find(curType)==sg.end())
6266             {
6267               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6268               sg.insert(curType);
6269             }
6270           else
6271             return false;
6272         }
6273     }
6274   return true;
6275 }
6276
6277 /*!
6278  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6279  * 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
6280  * 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'.
6281  */
6282 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6283 {
6284   checkConnectivityFullyDefined();
6285   mcIdType nbOfCells=getNumberOfCells();
6286   const mcIdType *conn=_nodal_connec->begin();
6287   const mcIdType *connI=_nodal_connec_index->begin();
6288   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6289   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6290   tmpa->alloc(nbOfCells,1);
6291   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6292   tmpb->fillWithZero();
6293   mcIdType *tmp=tmpa->getPointer();
6294   mcIdType *tmp2=tmpb->getPointer();
6295   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6296     {
6297       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6298       if(where!=orderEnd)
6299         {
6300           mcIdType pos=ToIdType(std::distance(orderBg,where));
6301           tmp2[pos]++;
6302           tmp[std::distance(connI,i)]=pos;
6303         }
6304       else
6305         {
6306           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6307           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6308           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6309           throw INTERP_KERNEL::Exception(oss.str());
6310         }
6311     }
6312   nbPerType=tmpb.retn();
6313   return tmpa.retn();
6314 }
6315
6316 /*!
6317  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6318  *
6319  * \return a new object containing the old to new correspondence.
6320  *
6321  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6322  */
6323 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6324 {
6325   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6326 }
6327
6328 /*!
6329  * 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.
6330  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6331  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6332  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6333  */
6334 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6335 {
6336   DataArrayIdType *nbPerType=0;
6337   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6338   nbPerType->decrRef();
6339   return tmpa->buildPermArrPerLevel();
6340 }
6341
6342 /*!
6343  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6344  * The number of cells remains unchanged after the call of this method.
6345  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6346  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6347  *
6348  * \return the array giving the correspondence old to new.
6349  */
6350 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6351 {
6352   checkFullyDefined();
6353   computeTypes();
6354   const mcIdType *conn=_nodal_connec->begin();
6355   const mcIdType *connI=_nodal_connec_index->begin();
6356   mcIdType nbOfCells=getNumberOfCells();
6357   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6358   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6359     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6360       {
6361         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6362         types.push_back(curType);
6363         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6364       }
6365   DataArrayIdType *ret=DataArrayIdType::New();
6366   ret->alloc(nbOfCells,1);
6367   mcIdType *retPtr=ret->getPointer();
6368   std::fill(retPtr,retPtr+nbOfCells,-1);
6369   mcIdType newCellId=0;
6370   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6371     {
6372       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6373         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6374           retPtr[std::distance(connI,i)]=newCellId++;
6375     }
6376   renumberCells(retPtr,false);
6377   return ret;
6378 }
6379
6380 /*!
6381  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6382  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6383  * This method makes asumption that connectivity is correctly set before calling.
6384  */
6385 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6386 {
6387   checkConnectivityFullyDefined();
6388   const mcIdType *conn=_nodal_connec->begin();
6389   const mcIdType *connI=_nodal_connec_index->begin();
6390   mcIdType nbOfCells=getNumberOfCells();
6391   std::vector<MEDCouplingUMesh *> ret;
6392   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6393     {
6394       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6395       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6396       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6397       mcIdType endCellId=ToIdType(std::distance(connI,i));
6398       mcIdType sz=endCellId-beginCellId;
6399       mcIdType *cells=new mcIdType[sz];
6400       for(mcIdType j=0;j<sz;j++)
6401         cells[j]=beginCellId+j;
6402       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6403       delete [] cells;
6404       ret.push_back(m);
6405     }
6406   return ret;
6407 }
6408
6409 /*!
6410  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6411  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6412  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6413  *
6414  * \return a newly allocated instance, that the caller must manage.
6415  * \throw If \a this contains more than one geometric type.
6416  * \throw If the nodal connectivity of \a this is not fully defined.
6417  * \throw If the internal data is not coherent.
6418  */
6419 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6420 {
6421   checkConnectivityFullyDefined();
6422   if(_types.size()!=1)
6423     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6424   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6425   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6426   ret->setCoords(getCoords());
6427   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6428   if(retC)
6429     {
6430       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6431       retC->setNodalConnectivity(c);
6432     }
6433   else
6434     {
6435       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6436       if(!retD)
6437         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6438       DataArrayIdType *c=0,*ci=0;
6439       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6440       MCAuto<DataArrayIdType> cs(c),cis(ci);
6441       retD->setNodalConnectivity(cs,cis);
6442     }
6443   return ret.retn();
6444 }
6445
6446 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6447 {
6448   checkConnectivityFullyDefined();
6449   if(_types.size()!=1)
6450     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6451   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6452   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6453   if(cm.isDynamic())
6454     {
6455       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6456       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6457       throw INTERP_KERNEL::Exception(oss.str());
6458     }
6459   mcIdType nbCells=getNumberOfCells();
6460   mcIdType typi=ToIdType(typ);
6461   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6462   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6463   mcIdType *outPtr=connOut->getPointer();
6464   const mcIdType *conn=_nodal_connec->begin();
6465   const mcIdType *connI=_nodal_connec_index->begin();
6466   nbNodesPerCell++;
6467   for(mcIdType i=0;i<nbCells;i++,connI++)
6468     {
6469       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6470         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6471       else
6472         {
6473           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 << ") !";
6474           throw INTERP_KERNEL::Exception(oss.str());
6475         }
6476     }
6477   return connOut.retn();
6478 }
6479
6480 /*!
6481  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6482  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6483  * \param nodalConn nodal connectivity
6484  * \param nodalConnIndex nodal connectivity indices
6485  */
6486 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6487 {
6488   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6489   checkConnectivityFullyDefined();
6490   if(_types.size()!=1)
6491     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6492   mcIdType nbCells=getNumberOfCells(),
6493            lgth=_nodal_connec->getNumberOfTuples();
6494   if(lgth<nbCells)
6495     throw INTERP_KERNEL::Exception(msg0);
6496   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6497   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6498   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6499   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6500   cip[0]=0;
6501   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6502     {
6503       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6504       mcIdType delta(stop-strt);
6505       if(delta>=1)
6506         {
6507           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6508             cp=std::copy(incp+strt,incp+stop,cp);
6509           else
6510             throw INTERP_KERNEL::Exception(msg0);
6511         }
6512       else
6513         throw INTERP_KERNEL::Exception(msg0);
6514       cip[1]=cip[0]+delta;
6515     }
6516   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6517 }
6518
6519 /*!
6520  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6521  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6522  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6523  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6524  * are not used here to avoid the build of big permutation array.
6525  *
6526  * \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
6527  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6528  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6529  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6530  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6531  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6532  * \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
6533  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6534  */
6535 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6536                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6537                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6538 {
6539   std::vector<const MEDCouplingUMesh *> ms2;
6540   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6541     if(*it)
6542       {
6543         (*it)->checkConnectivityFullyDefined();
6544         ms2.push_back(*it);
6545       }
6546   if(ms2.empty())
6547     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6548   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6549   int meshDim=ms2[0]->getMeshDimension();
6550   std::vector<const MEDCouplingUMesh *> m1ssm;
6551   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6552   //
6553   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6554   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6555   mcIdType fake=0,rk=0;
6556   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6557   ret1->alloc(0,1); ret2->alloc(0,1);
6558   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6559     {
6560       if(meshDim!=(*it)->getMeshDimension())
6561         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6562       if(refCoo!=(*it)->getCoords())
6563         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6564       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6565       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6566       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6567       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6568         {
6569           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6570           m1ssmSingleAuto.push_back(singleCell);
6571           m1ssmSingle.push_back(singleCell);
6572           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6573         }
6574     }
6575   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6576   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6577   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6578   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6579     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6580   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6581   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6582   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6583   return ret0.retn();
6584 }
6585
6586 /*!
6587  * This method returns a newly created DataArrayIdType instance.
6588  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6589  */
6590 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6591 {
6592   checkFullyDefined();
6593   const mcIdType *conn=_nodal_connec->begin();
6594   const mcIdType *connIndex=_nodal_connec_index->begin();
6595   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6596   for(const mcIdType *w=begin;w!=end;w++)
6597     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6598       ret->pushBackSilent(*w);
6599   return ret.retn();
6600 }
6601
6602 /*!
6603  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6604  * are in [0:getNumberOfCells())
6605  */
6606 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6607 {
6608   checkFullyDefined();
6609   const mcIdType *conn=_nodal_connec->begin();
6610   const mcIdType *connI=_nodal_connec_index->begin();
6611   mcIdType nbOfCells=getNumberOfCells();
6612   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6613   mcIdType *tmp=new mcIdType[nbOfCells];
6614   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6615     {
6616       mcIdType j=0;
6617       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6618         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6619           tmp[std::distance(connI,i)]=j++;
6620     }
6621   DataArrayIdType *ret=DataArrayIdType::New();
6622   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6623   ret->copyStringInfoFrom(*da);
6624   mcIdType *retPtr=ret->getPointer();
6625   const mcIdType *daPtr=da->begin();
6626   mcIdType nbOfElems=da->getNbOfElems();
6627   for(mcIdType k=0;k<nbOfElems;k++)
6628     retPtr[k]=tmp[daPtr[k]];
6629   delete [] tmp;
6630   return ret;
6631 }
6632
6633 /*!
6634  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6635  * This method \b works \b for mesh sorted by type.
6636  * cells whose ids is in 'idsPerGeoType' array.
6637  * This method conserves coords and name of mesh.
6638  */
6639 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6640 {
6641   std::vector<mcIdType> code=getDistributionOfTypes();
6642   std::size_t nOfTypesInThis=code.size()/3;
6643   mcIdType sz=0,szOfType=0;
6644   for(std::size_t i=0;i<nOfTypesInThis;i++)
6645     {
6646       if(code[3*i]!=type)
6647         sz+=code[3*i+1];
6648       else
6649         szOfType=code[3*i+1];
6650     }
6651   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6652     if(*work<0 || *work>=szOfType)
6653       {
6654         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6655         oss << ". It should be in [0," << szOfType << ") !";
6656         throw INTERP_KERNEL::Exception(oss.str());
6657       }
6658   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6659   mcIdType *idsPtr=idsTokeep->getPointer();
6660   mcIdType offset=0;
6661   for(std::size_t i=0;i<nOfTypesInThis;i++)
6662     {
6663       if(code[3*i]!=type)
6664         for(mcIdType j=0;j<code[3*i+1];j++)
6665           *idsPtr++=offset+j;
6666       else
6667         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6668       offset+=code[3*i+1];
6669     }
6670   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6671   ret->copyTinyInfoFrom(this);
6672   return ret.retn();
6673 }
6674
6675 /*!
6676  * This method returns a vector of size 'this->getNumberOfCells()'.
6677  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6678  */
6679 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6680 {
6681   mcIdType ncell=getNumberOfCells();
6682   std::vector<bool> ret(ncell);
6683   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6684   const mcIdType *c=getNodalConnectivity()->begin();
6685   for(mcIdType i=0;i<ncell;i++)
6686     {
6687       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6688       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6689       ret[i]=cm.isQuadratic();
6690     }
6691   return ret;
6692 }
6693
6694 /*!
6695  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6696  */
6697 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6698 {
6699   if(other->getType()!=UNSTRUCTURED)
6700     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6701   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6702   return MergeUMeshes(this,otherC);
6703 }
6704
6705 /*!
6706  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6707  * computed by averaging coordinates of cell nodes, so this method is not a right
6708  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6709  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6710  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6711  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6712  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6713  *          components. The caller is to delete this array using decrRef() as it is
6714  *          no more needed.
6715  *  \throw If the coordinates array is not set.
6716  *  \throw If the nodal connectivity of cells is not defined.
6717  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6718  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6719  */
6720 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6721 {
6722   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6723   int spaceDim=getSpaceDimension();
6724   mcIdType nbOfCells=getNumberOfCells();
6725   ret->alloc(nbOfCells,spaceDim);
6726   ret->copyStringInfoFrom(*getCoords());
6727   double *ptToFill=ret->getPointer();
6728   const mcIdType *nodal=_nodal_connec->begin();
6729   const mcIdType *nodalI=_nodal_connec_index->begin();
6730   const double *coor=_coords->begin();
6731   for(mcIdType i=0;i<nbOfCells;i++)
6732     {
6733       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6734       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6735       ptToFill+=spaceDim;
6736     }
6737   return ret.retn();
6738 }
6739
6740
6741 /*!
6742  * See computeCellCenterOfMass().
6743  *  \param eps a precision for the detection of degenerated arc of circles.
6744  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6745  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6746  *          components. The caller is to delete this array using decrRef() as it is
6747  *          no more needed.
6748  *  \throw If the coordinates array is not set.
6749  *  \throw If the nodal connectivity of cells is not defined.
6750  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6751  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6752  */
6753 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6754 {
6755   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6756   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6757   return ret.retn();
6758 }
6759
6760
6761 /*!
6762  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6763  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6764  *
6765  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6766  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6767  *
6768  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6769  * \throw If \a this is not fully defined (coordinates and connectivity)
6770  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6771  */
6772 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6773 {
6774   checkFullyDefined();
6775   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6776   int spaceDim=getSpaceDimension();
6777   mcIdType nbOfCells=getNumberOfCells();
6778   mcIdType nbOfNodes=getNumberOfNodes();
6779   ret->alloc(nbOfCells,spaceDim);
6780   double *ptToFill=ret->getPointer();
6781   const mcIdType *nodal=_nodal_connec->begin();
6782   const mcIdType *nodalI=_nodal_connec_index->begin();
6783   const double *coor=_coords->begin();
6784   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6785     {
6786       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6787       std::fill(ptToFill,ptToFill+spaceDim,0.);
6788       if(type!=INTERP_KERNEL::NORM_POLYHED)
6789         {
6790           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6791             {
6792               if(*conn>=0 && *conn<nbOfNodes)
6793                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6794               else
6795                 {
6796                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6797                   throw INTERP_KERNEL::Exception(oss.str());
6798                 }
6799             }
6800           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6801           if(nbOfNodesInCell>0)
6802             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6803           else
6804             {
6805               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6806               throw INTERP_KERNEL::Exception(oss.str());
6807             }
6808         }
6809       else
6810         {
6811           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6812           s.erase(-1);
6813           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6814             {
6815               if(*it>=0 && *it<nbOfNodes)
6816                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6817               else
6818                 {
6819                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6820                   throw INTERP_KERNEL::Exception(oss.str());
6821                 }
6822             }
6823           if(!s.empty())
6824             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6825           else
6826             {
6827               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6828               throw INTERP_KERNEL::Exception(oss.str());
6829             }
6830         }
6831     }
6832   return ret.retn();
6833 }
6834
6835 /*!
6836  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6837  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6838  * are specified via an array of cell ids.
6839  *  \warning Validity of the specified cell ids is not checked!
6840  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6841  *  \param [in] begin - an array of cell ids of interest.
6842  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6843  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6844  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6845  *          caller is to delete this array using decrRef() as it is no more needed.
6846  *  \throw If the coordinates array is not set.
6847  *  \throw If the nodal connectivity of cells is not defined.
6848  *
6849  *  \if ENABLE_EXAMPLES
6850  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6851  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6852  *  \endif
6853  */
6854 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6855 {
6856   DataArrayDouble *ret=DataArrayDouble::New();
6857   int spaceDim=getSpaceDimension();
6858   std::size_t nbOfTuple=std::distance(begin,end);
6859   ret->alloc(nbOfTuple,spaceDim);
6860   double *ptToFill=ret->getPointer();
6861   double *tmp=new double[spaceDim];
6862   const mcIdType *nodal=_nodal_connec->begin();
6863   const mcIdType *nodalI=_nodal_connec_index->begin();
6864   const double *coor=_coords->begin();
6865   for(const mcIdType *w=begin;w!=end;w++)
6866     {
6867       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6868       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6869       ptToFill+=spaceDim;
6870     }
6871   delete [] tmp;
6872   return ret;
6873 }
6874
6875 /*!
6876  * 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".
6877  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6878  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6879  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6880  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6881  *
6882  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6883  * \throw If spaceDim!=3 or meshDim!=2.
6884  * \throw If connectivity of \a this is invalid.
6885  * \throw If connectivity of a cell in \a this points to an invalid node.
6886  */
6887 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6888 {
6889   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6890   mcIdType nbOfCells=getNumberOfCells();
6891   mcIdType nbOfNodes(getNumberOfNodes());
6892   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6893     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6894   ret->alloc(nbOfCells,4);
6895   double *retPtr(ret->getPointer());
6896   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6897   const double *coor(_coords->begin());
6898   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6899     {
6900       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6901       if(nodalI[1]-nodalI[0]>=4)
6902         {
6903           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6904                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6905                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6906           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6907                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6908                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6909           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]};
6910           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]));
6911           for(int j=0;j<3;j++)
6912             {
6913               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6914               if(nodeId>=0 && nodeId<nbOfNodes)
6915                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6916               else
6917                 {
6918                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6919                   throw INTERP_KERNEL::Exception(oss.str());
6920                 }
6921             }
6922           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6923             {
6924               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6925               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6926             }
6927           else
6928             {
6929               if(nodalI[1]-nodalI[0]==4)
6930                 {
6931                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6932                   throw INTERP_KERNEL::Exception(oss.str());
6933                 }
6934               //
6935               double dd[3]={0.,0.,0.};
6936               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6937                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6938               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6939               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6940               std::copy(dd,dd+3,matrix+4*2);
6941               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6942               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6943             }
6944         }
6945       else
6946         {
6947           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6948           throw INTERP_KERNEL::Exception(oss.str());
6949         }
6950     }
6951   return ret.retn();
6952 }
6953
6954 /*!
6955  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6956  *
6957  */
6958 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6959 {
6960   if(!da)
6961     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6962   da->checkAllocated();
6963   std::string name(da->getName());
6964   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6965   if(name.empty())
6966     ret->setName("Mesh");
6967   ret->setCoords(da);
6968   mcIdType nbOfTuples(da->getNumberOfTuples());
6969   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6970   c->alloc(2*nbOfTuples,1);
6971   cI->alloc(nbOfTuples+1,1);
6972   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6973   *cip++=0;
6974   for(mcIdType i=0;i<nbOfTuples;i++)
6975     {
6976       *cp++=INTERP_KERNEL::NORM_POINT1;
6977       *cp++=i;
6978       *cip++=2*(i+1);
6979     }
6980   ret->setConnectivity(c,cI,true);
6981   return ret.retn();
6982 }
6983
6984 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6985 {
6986   if(!da)
6987     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6988   da->checkAllocated();
6989   std::string name(da->getName());
6990   MCAuto<MEDCouplingUMesh> ret;
6991   {
6992     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6993     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6994     arr->alloc(da->getNumberOfTuples());
6995     tmp->setCoordsAt(0,arr);
6996     ret=tmp->buildUnstructured();
6997   }
6998   ret->setCoords(da);
6999   if(name.empty())
7000     ret->setName("Mesh");
7001   else
7002     ret->setName(name);
7003   return ret;
7004 }
7005
7006 /*!
7007  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7008  * Cells and nodes of
7009  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7010  *  \param [in] mesh1 - the first mesh.
7011  *  \param [in] mesh2 - the second mesh.
7012  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7013  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7014  *          is no more needed.
7015  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7016  *  \throw If the coordinates array is not set in none of the meshes.
7017  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7018  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7019  */
7020 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7021 {
7022   std::vector<const MEDCouplingUMesh *> tmp(2);
7023   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7024   return MergeUMeshes(tmp);
7025 }
7026
7027 /*!
7028  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7029  * Cells and nodes of
7030  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7031  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7032  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7033  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7034  *          is no more needed.
7035  *  \throw If \a a.size() == 0.
7036  *  \throw If \a a[ *i* ] == NULL.
7037  *  \throw If the coordinates array is not set in none of the meshes.
7038  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7039  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7040  */
7041 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7042 {
7043   std::size_t sz=a.size();
7044   if(sz==0)
7045     return MergeUMeshesLL(a);
7046   for(std::size_t ii=0;ii<sz;ii++)
7047     if(!a[ii])
7048       {
7049         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7050         throw INTERP_KERNEL::Exception(oss.str());
7051       }
7052   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7053   std::vector< const MEDCouplingUMesh * > aa(sz);
7054   int spaceDim=-3;
7055   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7056     {
7057       const MEDCouplingUMesh *cur=a[i];
7058       const DataArrayDouble *coo=cur->getCoords();
7059       if(coo)
7060         spaceDim=int(coo->getNumberOfComponents());
7061     }
7062   if(spaceDim==-3)
7063     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7064   for(std::size_t i=0;i<sz;i++)
7065     {
7066       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7067       aa[i]=bb[i];
7068     }
7069   return MergeUMeshesLL(aa);
7070 }
7071
7072 /*!
7073  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7074  * dimension and sharing the node coordinates array.
7075  * All cells of the first mesh precede all cells of the second mesh
7076  * within the result mesh.
7077  *  \param [in] mesh1 - the first mesh.
7078  *  \param [in] mesh2 - the second mesh.
7079  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7080  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7081  *          is no more needed.
7082  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7083  *  \throw If the meshes do not share the node coordinates array.
7084  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7085  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7086  */
7087 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7088 {
7089   std::vector<const MEDCouplingUMesh *> tmp(2);
7090   tmp[0]=mesh1; tmp[1]=mesh2;
7091   return MergeUMeshesOnSameCoords(tmp);
7092 }
7093
7094 /*!
7095  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7096  * dimension and sharing the node coordinates array.
7097  * All cells of the *i*-th mesh precede all cells of the
7098  * (*i*+1)-th mesh within the result mesh.
7099  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7100  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7101  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7102  *          is no more needed.
7103  *  \throw If \a a.size() == 0.
7104  *  \throw If \a a[ *i* ] == NULL.
7105  *  \throw If the meshes do not share the node coordinates array.
7106  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7107  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7108  */
7109 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7110 {
7111   if(meshes.empty())
7112     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7113   for(std::size_t ii=0;ii<meshes.size();ii++)
7114     if(!meshes[ii])
7115       {
7116         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7117         throw INTERP_KERNEL::Exception(oss.str());
7118       }
7119   const DataArrayDouble *coords=meshes.front()->getCoords();
7120   int meshDim=meshes.front()->getMeshDimension();
7121   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7122   mcIdType meshLgth=0;
7123   mcIdType meshIndexLgth=0;
7124   for(;iter!=meshes.end();iter++)
7125     {
7126       if(coords!=(*iter)->getCoords())
7127         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7128       if(meshDim!=(*iter)->getMeshDimension())
7129         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7130       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7131       meshIndexLgth+=(*iter)->getNumberOfCells();
7132     }
7133   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7134   nodal->alloc(meshLgth,1);
7135   mcIdType *nodalPtr=nodal->getPointer();
7136   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7137   nodalIndex->alloc(meshIndexLgth+1,1);
7138   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7139   mcIdType offset=0;
7140   for(iter=meshes.begin();iter!=meshes.end();iter++)
7141     {
7142       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7143       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7144       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7145       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7146       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7147       if(iter!=meshes.begin())
7148         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7149       else
7150         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7151       offset+=meshLgth2;
7152     }
7153   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7154   ret->setName("merge");
7155   ret->setMeshDimension(meshDim);
7156   ret->setConnectivity(nodal,nodalIndex,true);
7157   ret->setCoords(coords);
7158   return ret;
7159 }
7160
7161 /*!
7162  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7163  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7164  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7165  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7166  * New" mode are returned for each input mesh.
7167  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7168  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7169  *          valid values [0,1,2], see zipConnectivityTraducer().
7170  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7171  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7172  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7173  *          no more needed.
7174  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7175  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7176  *          is no more needed.
7177  *  \throw If \a meshes.size() == 0.
7178  *  \throw If \a meshes[ *i* ] == NULL.
7179  *  \throw If the meshes do not share the node coordinates array.
7180  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7181  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7182  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7183  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7184  */
7185 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7186 {
7187   //All checks are delegated to MergeUMeshesOnSameCoords
7188   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7189   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7190   corr.resize(meshes.size());
7191   std::size_t nbOfMeshes=meshes.size();
7192   mcIdType offset=0;
7193   const mcIdType *o2nPtr=o2n->begin();
7194   for(std::size_t i=0;i<nbOfMeshes;i++)
7195     {
7196       DataArrayIdType *tmp=DataArrayIdType::New();
7197       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7198       tmp->alloc(curNbOfCells,1);
7199       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7200       offset+=curNbOfCells;
7201       tmp->setName(meshes[i]->getName());
7202       corr[i]=tmp;
7203     }
7204   return ret.retn();
7205 }
7206
7207 /*!
7208  * Makes all given meshes share the nodal connectivity array. The common connectivity
7209  * array is created by concatenating the connectivity arrays of all given meshes. All
7210  * the given meshes must be of the same space dimension but dimension of cells **can
7211  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7212  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7213  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7214  *  \param [in,out] meshes - a vector of meshes to update.
7215  *  \throw If any of \a meshes is NULL.
7216  *  \throw If the coordinates array is not set in any of \a meshes.
7217  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7218  *  \throw If \a meshes are of different space dimension.
7219  */
7220 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7221 {
7222   std::size_t sz=meshes.size();
7223   if(sz==0 || sz==1)
7224     return;
7225   std::vector< const DataArrayDouble * > coords(meshes.size());
7226   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7227   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7228     {
7229       if((*it))
7230         {
7231           (*it)->checkConnectivityFullyDefined();
7232           const DataArrayDouble *coo=(*it)->getCoords();
7233           if(coo)
7234             *it2=coo;
7235           else
7236             {
7237               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7238               oss << " has no coordinate array defined !";
7239               throw INTERP_KERNEL::Exception(oss.str());
7240             }
7241         }
7242       else
7243         {
7244           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7245           oss << " is null !";
7246           throw INTERP_KERNEL::Exception(oss.str());
7247         }
7248     }
7249   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7250   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7251   mcIdType offset=(*it)->getNumberOfNodes();
7252   (*it++)->setCoords(res);
7253   for(;it!=meshes.end();it++)
7254     {
7255       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7256       (*it)->setCoords(res);
7257       (*it)->shiftNodeNumbersInConn(offset);
7258       offset+=oldNumberOfNodes;
7259     }
7260 }
7261
7262 /*!
7263  * Merges nodes coincident with a given precision within all given meshes that share
7264  * the nodal connectivity array. The given meshes **can be of different** mesh
7265  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7266  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7267  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7268  *  \param [in,out] meshes - a vector of meshes to update.
7269  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7270  *  \throw If any of \a meshes is NULL.
7271  *  \throw If the \a meshes do not share the same node coordinates array.
7272  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7273  */
7274 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7275 {
7276   if(meshes.empty())
7277     return ;
7278   std::set<const DataArrayDouble *> s;
7279   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7280     {
7281       if(*it)
7282         s.insert((*it)->getCoords());
7283       else
7284         {
7285           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 !";
7286           throw INTERP_KERNEL::Exception(oss.str());
7287         }
7288     }
7289   if(s.size()!=1)
7290     {
7291       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 !";
7292       throw INTERP_KERNEL::Exception(oss.str());
7293     }
7294   const DataArrayDouble *coo=*(s.begin());
7295   if(!coo)
7296     return;
7297   //
7298   DataArrayIdType *comm,*commI;
7299   coo->findCommonTuples(eps,-1,comm,commI);
7300   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7301   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7302   mcIdType newNbOfNodes;
7303   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7304   if(oldNbOfNodes==newNbOfNodes)
7305     return ;
7306   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7307   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7308     {
7309       (*it)->renumberNodesInConn(o2n->begin());
7310       (*it)->setCoords(newCoords);
7311     }
7312 }
7313
7314
7315 /*!
7316  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7317  */
7318 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7319 {
7320   std::size_t i, ip1;
7321   double v[3]={0.,0.,0.};
7322   std::size_t sz=std::distance(begin,end);
7323   if(!isQuadratic)
7324     for(i=0;i<sz;i++)
7325       {
7326         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7327         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7328         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];
7329         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7330         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7331       }
7332   else
7333     {
7334       // Same algorithm as above but also using intermediate quadratic points.
7335       // (taking only linear points might lead to issues if the linearized version of the
7336       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7337       std::size_t hsz = sz/2;
7338       for(std::size_t j=0;j<sz;j++)
7339         {
7340           if (j%2)  // current point i is quadratic, next point i+1 is standard
7341             {
7342               i = hsz+(j-1)/2;
7343               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7344             }
7345           else      // current point i is standard, next point i+1 is quadratic
7346             {
7347               i = j/2;
7348               ip1 = j/2+hsz;
7349             }
7350           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7351           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7352           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7353         }
7354     }
7355   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7356   return (ret>0.);
7357 }
7358
7359 /*!
7360  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7361  */
7362 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7363 {
7364   std::vector<std::pair<mcIdType,mcIdType> > edges;
7365   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7366   const mcIdType *bgFace=begin;
7367   for(std::size_t i=0;i<nbOfFaces;i++)
7368     {
7369       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7370       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7371       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7372         {
7373           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7374           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7375             return false;
7376           edges.push_back(p1);
7377         }
7378       bgFace=endFace+1;
7379     }
7380   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7381 }
7382
7383 /*!
7384  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7385  */
7386 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7387 {
7388   double vec0[3],vec1[3];
7389   std::size_t sz=std::distance(begin,end);
7390   if(sz%2!=0)
7391     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7392   mcIdType nbOfNodes=ToIdType(sz/2);
7393   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7394   const double *pt0=coords+3*begin[0];
7395   const double *pt1=coords+3*begin[nbOfNodes];
7396   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7397   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7398 }
7399
7400 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7401 {
7402   std::size_t sz=std::distance(begin,end);
7403   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7404   std::size_t nbOfNodes(sz/2);
7405   std::copy(begin,end,(mcIdType *)tmp);
7406   for(std::size_t j=1;j<nbOfNodes;j++)
7407     {
7408       begin[j]=tmp[nbOfNodes-j];
7409       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7410     }
7411 }
7412
7413 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7414 {
7415   std::size_t sz=std::distance(begin,end);
7416   if(sz!=4)
7417     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7418   double vec0[3],vec1[3];
7419   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7420   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];
7421   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;
7422 }
7423
7424 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7425 {
7426   std::size_t sz=std::distance(begin,end);
7427   if(sz!=5)
7428     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7429   double vec0[3];
7430   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7431   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7432   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7433 }
7434
7435 /*!
7436  * 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 )
7437  * 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
7438  * a 2D space.
7439  *
7440  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7441  * \param [in] coords the coordinates with nb of components exactly equal to 3
7442  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7443  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7444  */
7445 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7446                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7447 {
7448   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7449   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7450   double *vPtr=v->getPointer();
7451   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7452   double *pPtr=p->getPointer();
7453   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7454   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7455   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7456     {
7457       mcIdType face = e_f[e_fi[index] + i];
7458       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7459       // to differentiate faces going to different cells:
7460       pPtr++, *pPtr = 0;
7461       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7462         *pPtr += FromIdType<double>(f_e[j]);
7463     }
7464   pPtr=p->getPointer(); vPtr=v->getPointer();
7465   DataArrayIdType *comm1=0,*commI1=0;
7466   v->findCommonTuples(eps,-1,comm1,commI1);
7467   for (mcIdType i = 0; i < nbFaces; i++)
7468     if (comm1->findIdFirstEqual(i) < 0)
7469       {
7470         comm1->pushBackSilent(i);
7471         commI1->pushBackSilent(comm1->getNumberOfTuples());
7472       }
7473   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7474   const mcIdType *comm1Ptr=comm1->begin();
7475   const mcIdType *commI1Ptr=commI1->begin();
7476   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7477   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7478   //
7479   for(mcIdType i=0;i<nbOfGrps1;i++)
7480     {
7481       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7482       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7483       DataArrayIdType *comm2=0,*commI2=0;
7484       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7485       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7486         if (comm2->findIdFirstEqual(j) < 0)
7487           {
7488             comm2->pushBackSilent(j);
7489             commI2->pushBackSilent(comm2->getNumberOfTuples());
7490           }
7491       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7492       const mcIdType *comm2Ptr=comm2->begin();
7493       const mcIdType *commI2Ptr=commI2->begin();
7494       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7495       for(mcIdType j=0;j<nbOfGrps2;j++)
7496         {
7497           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7498             {
7499               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7500               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7501               res->pushBackSilent(-1);
7502             }
7503           else
7504             {
7505               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7506               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7507               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7508               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7509               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7510               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7511               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7512               const mcIdType *idsNodePtr=idsNode->begin();
7513               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];
7514               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7515               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7516               if(std::abs(norm)>eps)
7517                 {
7518                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7519                   mm3->rotate(center,vec,angle);
7520                 }
7521               mm3->changeSpaceDimension(2);
7522               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7523               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7524               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7525               mcIdType nbOfCells=mm4->getNumberOfCells();
7526               for(mcIdType k=0;k<nbOfCells;k++)
7527                 {
7528                   int l=0;
7529                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7530                     res->pushBackSilent(idsNodePtr[*work]);
7531                   res->pushBackSilent(-1);
7532                 }
7533             }
7534         }
7535     }
7536   res->popBackSilent();
7537 }
7538
7539 /*!
7540  * 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
7541  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7542  *
7543  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7544  * \param [in] coords coordinates expected to have 3 components.
7545  * \param [in] begin start of the nodal connectivity of the face.
7546  * \param [in] end end of the nodal connectivity (excluded) of the face.
7547  * \param [out] v the normalized vector of size 3
7548  * \param [out] p the pos of plane
7549  */
7550 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7551 {
7552   std::size_t nbPoints=std::distance(begin,end);
7553   if(nbPoints<3)
7554     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7555   double vec[3]={0.,0.,0.};
7556   std::size_t j=0;
7557   bool refFound=false;
7558   for(;j<nbPoints-1 && !refFound;j++)
7559     {
7560       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7561       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7562       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7563       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7564       if(norm>eps)
7565         {
7566           refFound=true;
7567           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7568         }
7569     }
7570   for(std::size_t i=j;i<nbPoints-1;i++)
7571     {
7572       double curVec[3];
7573       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7574       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7575       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7576       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7577       if(norm<eps)
7578         continue;
7579       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7580       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];
7581       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7582       if(norm>eps)
7583         {
7584           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7585           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7586           return ;
7587         }
7588     }
7589   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7590 }
7591
7592 /*!
7593  * This method tries to obtain a well oriented polyhedron.
7594  * If the algorithm fails, an exception will be thrown.
7595  */
7596 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7597 {
7598   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7599   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7600   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7601   isPerm[0]=true;
7602   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7603   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7604   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7605   //
7606   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7607     {
7608       bgFace=begin;
7609       std::size_t smthChanged=0;
7610       for(std::size_t i=0;i<nbOfFaces;i++)
7611         {
7612           endFace=std::find(bgFace+1,end,-1);
7613           nbOfEdgesInFace=std::distance(bgFace,endFace);
7614           if(!isPerm[i])
7615             {
7616               bool b=false;
7617               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7618                 {
7619                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7620                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7621                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7622                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7623                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7624                 }
7625               if(isPerm[i])
7626                 {
7627                   if(!b)
7628                     std::reverse(bgFace+1,endFace);
7629                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7630                     {
7631                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7632                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7633                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7634                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7635                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7636                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7637                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7638                       if(it!=edgesOK.end())
7639                         {
7640                           edgesOK.erase(it);
7641                           edgesFinished.push_back(p1);
7642                         }
7643                       else
7644                         edgesOK.push_back(p1);
7645                     }
7646                 }
7647             }
7648           bgFace=endFace+1;
7649         }
7650       if(smthChanged==0)
7651         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7652     }
7653   if(!edgesOK.empty())
7654     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7655   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7656     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7657       bgFace=begin;
7658       for(std::size_t i=0;i<nbOfFaces;i++)
7659         {
7660           endFace=std::find(bgFace+1,end,-1);
7661           std::reverse(bgFace+1,endFace);
7662           bgFace=endFace+1;
7663         }
7664     }
7665 }
7666
7667
7668 /*!
7669  * This method makes the assumption spacedimension == meshdimension == 2.
7670  * This method works only for linear cells.
7671  *
7672  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7673  */
7674 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7675 {
7676   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7677     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7678   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7679   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7680   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7681   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7682   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7683   mcIdType nbCells=skin->getNumberOfCells();
7684   if(nbCells==nbOfNodesExpected)
7685     return buildUnionOf2DMeshLinear(skin,n2o);
7686   else if(2*nbCells==nbOfNodesExpected)
7687     return buildUnionOf2DMeshQuadratic(skin,n2o);
7688   else
7689     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7690 }
7691
7692 /*!
7693  * This method makes the assumption spacedimension == meshdimension == 3.
7694  * This method works only for linear cells.
7695  *
7696  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7697  */
7698 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7699 {
7700   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7701     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7702   MCAuto<MEDCouplingUMesh> m=computeSkin();
7703   const mcIdType *conn=m->getNodalConnectivity()->begin();
7704   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7705   mcIdType nbOfCells=m->getNumberOfCells();
7706   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7707   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7708   if(nbOfCells<1)
7709     return ret.retn();
7710   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7711   for(mcIdType i=1;i<nbOfCells;i++)
7712     {
7713       *work++=-1;
7714       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7715     }
7716   return ret.retn();
7717 }
7718
7719 /*!
7720  * \brief Creates a graph of cell neighbors
7721  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7722  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7723  *  For example
7724  *  - index:  0 3 5 6 6
7725  *  - value:  1 2 3 2 3 3
7726  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7727  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7728  */
7729 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7730 {
7731   checkConnectivityFullyDefined();
7732
7733   int meshDim = this->getMeshDimension();
7734   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7735   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7736   this->getReverseNodalConnectivity(revConn,indexr);
7737   const mcIdType* indexr_ptr=indexr->begin();
7738   const mcIdType* revConn_ptr=revConn->begin();
7739
7740   const MEDCoupling::DataArrayIdType* index;
7741   const MEDCoupling::DataArrayIdType* conn;
7742   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7743   index=this->getNodalConnectivityIndex();
7744   mcIdType nbCells=this->getNumberOfCells();
7745   const mcIdType* index_ptr=index->begin();
7746   const mcIdType* conn_ptr=conn->begin();
7747
7748   //creating graph arcs (cell to cell relations)
7749   //arcs are stored in terms of (index,value) notation
7750   // 0 3 5 6 6
7751   // 1 2 3 2 3 3
7752   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7753   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7754
7755   //warning here one node have less than or equal effective number of cell with it
7756   //but cell could have more than effective nodes
7757   //because other equals nodes in other domain (with other global inode)
7758   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7759   std::vector <mcIdType> cell2cell;
7760   cell2cell.reserve(3*nbCells);
7761
7762   for (mcIdType icell=0; icell<nbCells;icell++)
7763     {
7764       std::map<mcIdType,mcIdType > counter;
7765       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7766         {
7767           mcIdType inode=conn_ptr[iconn];
7768           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7769             {
7770               mcIdType icell2=revConn_ptr[iconnr];
7771               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7772               if (iter!=counter.end()) (iter->second)++;
7773               else counter.insert(std::make_pair(icell2,1));
7774             }
7775         }
7776       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7777            iter!=counter.end(); iter++)
7778         if (iter->second >= meshDim)
7779           {
7780             cell2cell_index[icell+1]++;
7781             cell2cell.push_back(iter->first);
7782           }
7783     }
7784   indexr->decrRef();
7785   revConn->decrRef();
7786   cell2cell_index[0]=0;
7787   for (mcIdType icell=0; icell<nbCells;icell++)
7788     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7789
7790   //filling up index and value to create skylinearray structure
7791   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7792   return array;
7793 }
7794
7795
7796 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7797 {
7798   mcIdType nbOfCells=getNumberOfCells();
7799   if(nbOfCells<=0)
7800     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7801   ofs << "  <" << getVTKDataSetType() << ">\n";
7802   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7803   ofs << "      <PointData>\n" << pointData << std::endl;
7804   ofs << "      </PointData>\n";
7805   ofs << "      <CellData>\n" << cellData << std::endl;
7806   ofs << "      </CellData>\n";
7807   ofs << "      <Points>\n";
7808   if(getSpaceDimension()==3)
7809     _coords->writeVTK(ofs,8,"Points",byteData);
7810   else
7811     {
7812       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7813       coo->writeVTK(ofs,8,"Points",byteData);
7814     }
7815   ofs << "      </Points>\n";
7816   ofs << "      <Cells>\n";
7817   const mcIdType *cPtr=_nodal_connec->begin();
7818   const mcIdType *cIPtr=_nodal_connec_index->begin();
7819   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7820   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7821   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7822   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7823   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7824   mcIdType szFaceOffsets=0,szConn=0;
7825   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7826     {
7827       *w2=cPtr[cIPtr[i]];
7828       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7829         {
7830           *w1=-1;
7831           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7832           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7833         }
7834       else
7835         {
7836           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7837           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7838           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7839           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7840           w4=std::copy(c.begin(),c.end(),w4);
7841         }
7842     }
7843   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7844   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7845     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7846   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7847   types->writeVTK(ofs,8,"UInt8","types",byteData);
7848   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7849   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7850   if(szFaceOffsets!=0)
7851     {//presence of Polyhedra
7852       connectivity->reAlloc(szConn);
7853       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7854       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7855       w1=faces->getPointer();
7856       for(mcIdType i=0;i<nbOfCells;i++)
7857         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7858           {
7859             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7860             *w1++=nbFaces;
7861             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7862             for(mcIdType j=0;j<nbFaces;j++)
7863               {
7864                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7865                 *w1++=ToIdType(std::distance(w6,w5));
7866                 w1=std::copy(w6,w5,w1);
7867                 w6=w5+1;
7868               }
7869           }
7870       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7871     }
7872   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7873   ofs << "      </Cells>\n";
7874   ofs << "    </Piece>\n";
7875   ofs << "  </" << getVTKDataSetType() << ">\n";
7876 }
7877
7878 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7879 {
7880   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7881   if(_mesh_dim==-2)
7882     { stream << " Not set !"; return ; }
7883   stream << " Mesh dimension : " << _mesh_dim << ".";
7884   if(_mesh_dim==-1)
7885     return ;
7886   if(!_coords)
7887     { stream << " No coordinates set !"; return ; }
7888   if(!_coords->isAllocated())
7889     { stream << " Coordinates set but not allocated !"; return ; }
7890   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7891   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7892   if(!_nodal_connec_index)
7893     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7894   if(!_nodal_connec_index->isAllocated())
7895     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7896   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7897   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7898   if(cpt!=1 || lgth<1)
7899     return ;
7900   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7901 }
7902
7903 std::string MEDCouplingUMesh::getVTKDataSetType() const
7904 {
7905   return std::string("UnstructuredGrid");
7906 }
7907
7908 std::string MEDCouplingUMesh::getVTKFileExtension() const
7909 {
7910   return std::string("vtu");
7911 }
7912
7913
7914
7915 /**
7916  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7917  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7918  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7919  * The caller is to deal with the resulting DataArrayIdType.
7920  *  \throw If the coordinate array is not set.
7921  *  \throw If the nodal connectivity of the cells is not defined.
7922  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7923  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7924  *
7925  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7926  */
7927 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7928 {
7929   checkFullyDefined();
7930   if(getMeshDimension()!=1)
7931     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7932
7933   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7934   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7935   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7936   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7937   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7938   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7939   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7940   const mcIdType * dsi(_dsi->begin());
7941   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7942   m_points=0;
7943   if (dsii->getNumberOfTuples())
7944     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7945
7946   mcIdType nc=getNumberOfCells();
7947   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7948   result->alloc(nc,1);
7949
7950   // set of edges not used so far
7951   std::set<mcIdType> edgeSet;
7952   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7953
7954   mcIdType startSeg=0;
7955   mcIdType newIdx=0;
7956   // while we have points with only one neighbor segments
7957   do
7958     {
7959       std::list<mcIdType> linePiece;
7960       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7961       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7962         {
7963           // Fill the list forward (resp. backward) from the start segment:
7964           mcIdType activeSeg = startSeg;
7965           mcIdType prevPointId = -20;
7966           mcIdType ptId;
7967           while (!edgeSet.empty())
7968             {
7969               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7970                 {
7971                   if (direction==0)
7972                     linePiece.push_back(activeSeg);
7973                   else
7974                     linePiece.push_front(activeSeg);
7975                   edgeSet.erase(activeSeg);
7976                 }
7977
7978               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7979               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7980               if (dsi[ptId] == 1) // hitting the end of the line
7981                 break;
7982               prevPointId = ptId;
7983               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7984               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7985             }
7986         }
7987       // Done, save final piece into DA:
7988       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7989       newIdx += ToIdType(linePiece.size());
7990
7991       // identify next valid start segment (one which is not consumed)
7992       if(!edgeSet.empty())
7993         startSeg = *(edgeSet.begin());
7994     }
7995   while (!edgeSet.empty());
7996   return result.retn();
7997 }
7998
7999 /**
8000  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
8001  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
8002  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
8003  * a minimal creation of new nodes is wanted.
8004  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
8005  * nodes if a SEG3 is split without information of middle.
8006  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
8007  * avoid to have a non conform mesh.
8008  *
8009  * \return mcIdType - the number of new nodes created (in most of cases 0).
8010  *
8011  * \throw If \a this is not coherent.
8012  * \throw If \a this has not spaceDim equal to 2.
8013  * \throw If \a this has not meshDim equal to 2.
8014  * \throw If some subcells needed to be split are orphan.
8015  * \sa MEDCouplingUMesh::conformize2D
8016  */
8017 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8018 {
8019   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8020     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8021   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8022   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8023     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8024   if(midOpt==0 && midOptI==0)
8025     {
8026       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8027       return 0;
8028     }
8029   else if(midOpt!=0 && midOptI!=0)
8030     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8031   else
8032     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8033 }
8034
8035 /*!
8036  * 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
8037  * 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
8038  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8039  * 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
8040  * 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.
8041  *
8042  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8043  */
8044 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8045 {
8046   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8047   if(sz>=4)
8048     {
8049       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8050       if(cm.getDimension()==2)
8051         {
8052           const mcIdType *node=nodalConnBg+1;
8053           mcIdType startNode=*node++;
8054           double refX=coords[2*startNode];
8055           for(;node!=nodalConnEnd;node++)
8056             {
8057               if(coords[2*(*node)]<refX)
8058                 {
8059                   startNode=*node;
8060                   refX=coords[2*startNode];
8061                 }
8062             }
8063           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8064           refX=1e300;
8065           double tmp1;
8066           double tmp2[2];
8067           double angle0=-M_PI/2;
8068           //
8069           mcIdType nextNode=-1;
8070           mcIdType prevNode=-1;
8071           double resRef;
8072           double angleNext=0.;
8073           while(nextNode!=startNode)
8074             {
8075               nextNode=-1;
8076               resRef=1e300;
8077               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8078                 {
8079                   if(*node!=tmpOut.back() && *node!=prevNode)
8080                     {
8081                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8082                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8083                       double res;
8084                       if(angleM<=angle0)
8085                         res=angle0-angleM;
8086                       else
8087                         res=angle0-angleM+2.*M_PI;
8088                       if(res<resRef)
8089                         {
8090                           nextNode=*node;
8091                           resRef=res;
8092                           angleNext=angleM;
8093                         }
8094                     }
8095                 }
8096               if(nextNode!=startNode)
8097                 {
8098                   angle0=angleNext-M_PI;
8099                   if(angle0<-M_PI)
8100                     angle0+=2*M_PI;
8101                   prevNode=tmpOut.back();
8102                   tmpOut.push_back(nextNode);
8103                 }
8104             }
8105           std::vector<mcIdType> tmp3(2*(sz-1));
8106           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8107           std::copy(nodalConnBg+1,nodalConnEnd,it);
8108           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8109             {
8110               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8111               return false;
8112             }
8113           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8114             {
8115               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8116               return false;
8117             }
8118           else
8119             {
8120               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8121               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8122               return true;
8123             }
8124         }
8125       else
8126         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8127     }
8128   else
8129     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8130 }
8131
8132 /*!
8133  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8134  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8135  * 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]].
8136  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8137  * A negative value in \b arrIn means that it is ignored.
8138  * 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.
8139  *
8140  * \param [in] arrIn arr origin array from which the extraction will be done.
8141  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8142  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8143  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8144  */
8145 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8146 {
8147   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8148   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8149 }
8150
8151 /*!
8152  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8153  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8154  * 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]].
8155  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8156  * A negative value in \b arrIn means that it is ignored.
8157  * 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.
8158  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8159  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8160  * \param [in] arrIn arr origin array from which the extraction will be done.
8161  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8162  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8163  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8164  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8165  * \sa MEDCouplingUMesh::partitionBySpreadZone
8166  */
8167 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8168 {
8169   nbOfDepthPeelingPerformed=0;
8170   if(!arrIndxIn)
8171     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8172   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8173   if(nbOfTuples<=0)
8174     {
8175       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8176       return ret;
8177     }
8178   //
8179   std::vector<bool> fetched(nbOfTuples,false);
8180   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8181 }
8182
8183
8184
8185 /*!
8186  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8187  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8188  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8189  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8190  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8191  *
8192  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8193  */
8194 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8195 {
8196   checkFullyDefined();
8197   int mdim=getMeshDimension();
8198   int spaceDim=getSpaceDimension();
8199   if(mdim!=spaceDim)
8200     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8201   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8202   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8203   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8204   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8205   ret->setCoords(getCoords());
8206   ret->allocateCells(ToIdType(partition.size()));
8207   //
8208   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8209     {
8210       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8211       MCAuto<DataArrayIdType> cell;
8212       switch(mdim)
8213       {
8214         case 2:
8215           cell=tmp->buildUnionOf2DMesh();
8216           break;
8217         case 3:
8218           cell=tmp->buildUnionOf3DMesh();
8219           break;
8220         default:
8221           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8222       }
8223
8224       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8225     }
8226   //
8227   ret->finishInsertingCells();
8228   return ret.retn();
8229 }
8230
8231 /*!
8232  * This method partitions \b this into contiguous zone.
8233  * This method only needs a well defined connectivity. Coordinates are not considered here.
8234  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8235  */
8236 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8237 {
8238   DataArrayIdType *neigh=0,*neighI=0;
8239   computeNeighborsOfCells(neigh,neighI);
8240   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8241   return PartitionBySpreadZone(neighAuto,neighIAuto);
8242 }
8243
8244 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8245 {
8246   if(!arrIn || !arrIndxIn)
8247     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8248   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8249   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8250   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8251     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8252   mcIdType nbOfCellsCur(nbOfTuples-1);
8253   std::vector<DataArrayIdType *> ret;
8254   if(nbOfCellsCur<=0)
8255     return ret;
8256   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8257   std::vector< MCAuto<DataArrayIdType> > ret2;
8258   mcIdType seed=0;
8259   while(seed<nbOfCellsCur)
8260     {
8261       mcIdType nbOfPeelPerformed=0;
8262       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8263       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8264     }
8265   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8266     ret.push_back((*it).retn());
8267   return ret;
8268 }
8269
8270 /*!
8271  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8272  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8273  *
8274  * \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.
8275  * \return a newly allocated DataArrayIdType to be managed by the caller.
8276  * \throw In case of \a code has not the right format (typically of size 3*n)
8277  */
8278 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8279 {
8280   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8281   std::size_t nb=code.size()/3;
8282   if(code.size()%3!=0)
8283     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8284   ret->alloc(nb,2);
8285   mcIdType *retPtr=ret->getPointer();
8286   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8287     {
8288       retPtr[0]=code[3*i+2];
8289       retPtr[1]=code[3*i+2]+code[3*i+1];
8290     }
8291   return ret.retn();
8292 }
8293
8294 /*!
8295  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8296  * All cells in \a this are expected to be linear 3D cells.
8297  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8298  * It leads to an increase to number of cells.
8299  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8300  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8301  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8302  *
8303  * \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.
8304  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8305  * \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.
8306  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8307  *          an id of old cell producing it. The caller is to delete this array using
8308  *         decrRef() as it is no more needed.
8309  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8310  *
8311  * \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
8312  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8313  *
8314  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8315  * \throw If \a this is not fully constituted with linear 3D cells.
8316  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8317  */
8318 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8319 {
8320   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8321   checkConnectivityFullyDefined();
8322   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8323     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8324   mcIdType nbOfCells=getNumberOfCells();
8325   mcIdType nbNodes(getNumberOfNodes());
8326   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8327   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8328   mcIdType *retPt(ret->getPointer());
8329   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8330   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8331   const mcIdType *oldc(_nodal_connec->begin());
8332   const mcIdType *oldci(_nodal_connec_index->begin());
8333   const double *coords(_coords->begin());
8334   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8335     {
8336       std::vector<mcIdType> a; std::vector<double> b;
8337       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8338       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8339       const mcIdType *aa(&a[0]);
8340       if(!b.empty())
8341         {
8342           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8343             if(*it<0)
8344               *it=(-(*(it))-1+nbNodes);
8345           addPts->insertAtTheEnd(b.begin(),b.end());
8346           nbNodes+=ToIdType(b.size()/3);
8347         }
8348       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8349         newConn->insertAtTheEnd(aa,aa+4);
8350     }
8351   if(!addPts->empty())
8352     {
8353       addPts->rearrange(3);
8354       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8355       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8356       ret0->setCoords(addPts);
8357     }
8358   else
8359     {
8360       nbOfAdditionalPoints=0;
8361       ret0->setCoords(getCoords());
8362     }
8363   ret0->setNodalConnectivity(newConn);
8364   //
8365   ret->computeOffsetsFull();
8366   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8367   return ret0.retn();
8368 }
8369
8370 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8371     _own_cell(true),_cell_id(-1),_nb_cell(0)
8372 {
8373   if(mesh)
8374     {
8375       mesh->incrRef();
8376       _nb_cell=mesh->getNumberOfCells();
8377     }
8378 }
8379
8380 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8381 {
8382   if(_mesh)
8383     _mesh->decrRef();
8384   if(_own_cell)
8385     delete _cell;
8386 }
8387
8388 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8389     _own_cell(false),_cell_id(bg-1),
8390     _nb_cell(end)
8391 {
8392   if(mesh)
8393     mesh->incrRef();
8394 }
8395
8396 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8397 {
8398   _cell_id++;
8399   if(_cell_id<_nb_cell)
8400     {
8401       _cell->next();
8402       return _cell;
8403     }
8404   else
8405     return 0;
8406 }
8407
8408 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8409 {
8410   if(_mesh)
8411     _mesh->incrRef();
8412 }
8413
8414 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8415 {
8416   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8417 }
8418
8419 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8420 {
8421   if(_mesh)
8422     _mesh->decrRef();
8423 }
8424
8425 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8426     _itc(itc),
8427     _bg(bg),_end(end)
8428 {
8429   if(_mesh)
8430     _mesh->incrRef();
8431 }
8432
8433 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8434 {
8435   if(_mesh)
8436     _mesh->decrRef();
8437 }
8438
8439 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8440 {
8441   return _type;
8442 }
8443
8444 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8445 {
8446   return _end-_bg;
8447 }
8448
8449 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8450 {
8451   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8452 }
8453
8454 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8455 {
8456   if(mesh)
8457     {
8458       mesh->incrRef();
8459       _nb_cell=mesh->getNumberOfCells();
8460     }
8461 }
8462
8463 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8464 {
8465   if(_mesh)
8466     _mesh->decrRef();
8467   delete _cell;
8468 }
8469
8470 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8471 {
8472   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8473   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8474   if(_cell_id<_nb_cell)
8475     {
8476       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8477       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8478       mcIdType startId=_cell_id;
8479       _cell_id+=nbOfElems;
8480       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8481     }
8482   else
8483     return 0;
8484 }
8485
8486 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8487 {
8488   if(mesh)
8489     {
8490       _conn=mesh->getNodalConnectivity()->getPointer();
8491       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8492     }
8493 }
8494
8495 void MEDCouplingUMeshCell::next()
8496 {
8497   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8498     {
8499       _conn+=_conn_lgth;
8500       _conn_indx++;
8501     }
8502   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8503 }
8504
8505 std::string MEDCouplingUMeshCell::repr() const
8506 {
8507   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8508     {
8509       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8510       oss << " : ";
8511       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8512       return oss.str();
8513     }
8514   else
8515     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8516 }
8517
8518 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8519 {
8520   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8521     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8522   else
8523     return INTERP_KERNEL::NORM_ERROR;
8524 }
8525
8526 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8527 {
8528   lgth=_conn_lgth;
8529   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8530     return _conn;
8531   else
8532     return 0;
8533 }
8534
8535 /// @cond INTERNAL
8536
8537 namespace MEDCouplingImpl
8538 {
8539   const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8540
8541   //================================================================================
8542   /*!
8543    * \brief Encode a cell id and a mesh index into a code
8544    *  \param [in] id - cell id
8545    *  \param [in] iMesh - mesh index [0,1]
8546    *  \return mcIdType - code
8547    */
8548   //================================================================================
8549
8550   mcIdType encodeID( mcIdType id, int iMesh )
8551   {
8552     return ( id + 1 ) * ( iMesh ? -1 : 1 );
8553   }
8554   //================================================================================
8555   /*!
8556    * \brief Return cell id and mesh index by a given id
8557    *  \param [in] id - code of a cell in a mesh
8558    *  \param [out] iMesh - returned mesh index
8559    *  \return mcIdType - cell id
8560    */
8561   //================================================================================
8562
8563   mcIdType decodeID( mcIdType id, int& iMesh )
8564   {
8565     iMesh = ( id < 0 );
8566     return std::abs( id ) - 1;
8567   }
8568
8569   //================================================================================
8570   /*!
8571    * \brief return another face sharing two given nodes of a face edge
8572    *  \param [in] n0 - 1st node of the edge
8573    *  \param [in] n1 - 2nd node of the edge
8574    *  \param [in] inputFaceID - face including \a n0 andf \a n2
8575    *  \param [in] mesh - object and reference meshes
8576    *  \param [in] revNodal - reverse nodal connectivity of the two meshes
8577    *  \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8578    *  \param [out] facesByEdge - return another face including \a n0 andf \a n2
8579    *  \param [out] equalFaces - return faces equal to facesByEdge
8580    */
8581   //================================================================================
8582
8583   void getFacesOfEdge( mcIdType n0,
8584                        mcIdType n1,
8585                        mcIdType inputFaceID,
8586                        MEDCouplingUMesh* mesh[],
8587                        MCAuto<DataArrayIdType> revNodal[],
8588                        MCAuto<DataArrayIdType> revNodalIndx[],
8589                        std::vector< mcIdType >& facesByEdge,
8590                        std::vector< mcIdType >& equalFaces)
8591   {
8592     // find faces sharing the both nodes of edge
8593
8594     facesByEdge.clear();
8595     size_t prevNbF; // nb faces found in 0-th mesh
8596     for ( int iM = 0; iM < 2; ++iM )
8597       {
8598         const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8599         const mcIdType * rev    = revNodal    [ iM ]->begin();
8600
8601         mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8602         mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8603
8604         prevNbF = facesByEdge.size();
8605         facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8606
8607         auto it = std::set_intersection( rev + revInd[ n0 ],
8608                                          rev + revInd[ n0 ] + nbRevFaces0,
8609                                          rev + revInd[ n1 ],
8610                                          rev + revInd[ n1 ] + nbRevFaces1,
8611                                          facesByEdge.begin() + prevNbF );
8612         facesByEdge.resize( it - facesByEdge.begin() );
8613       }
8614
8615     // facesByEdge now contains at least the 'inputFaceID'
8616     // check if there are other faces
8617
8618     size_t nbF = facesByEdge.size();
8619     if ( nbF > 1 )
8620       {
8621         if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8622           {
8623             // remove from facesByEdge equal faces in different meshes
8624             const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8625                                          mesh[1]->getNodalConnectivity()->getConstPointer() };
8626             const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8627                                          mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8628             for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8629               {
8630                 if ( facesByEdge[ i0 ] == theUndefID )
8631                   continue;
8632                 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8633                 bool   isInputFace = ( objFaceID == inputFaceID );
8634
8635                 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8636                   {
8637                     if ( facesByEdge[ i1 ] == theUndefID )
8638                       continue;
8639
8640                     mcIdType f0 = facesByEdge[ i0 ];
8641                     mcIdType f1 = facesByEdge[ i1 ];
8642                     size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8643                     size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8644                     if ( nbNodes0 != nbNodes1 )
8645                       continue;
8646
8647                     const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8648                     const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8649                     if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8650                       {
8651                         // equal faces; remove an object one
8652                         mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8653                         if ( refFaceID == inputFaceID )
8654                           isInputFace = true;
8655
8656                         if ( std::find( equalFaces.begin(),
8657                                         equalFaces.end(), objFaceID ) == equalFaces.end() )
8658                           equalFaces.push_back( objFaceID );
8659
8660                         facesByEdge[ i0 ] = theUndefID;
8661                         if ( isInputFace )
8662                           facesByEdge[ i1 ] = theUndefID;
8663                         break;
8664                       }
8665                   }
8666                 if ( isInputFace )
8667                   facesByEdge[ i0 ] = theUndefID;
8668               }
8669           }
8670       }
8671
8672     nbF = facesByEdge.size();
8673     for ( size_t i = 0; i < facesByEdge.size(); ++i )
8674       {
8675         if ( facesByEdge[ i ] != theUndefID )
8676           {
8677             facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8678             if ( facesByEdge[ i ] == inputFaceID )
8679               facesByEdge[ i ] = theUndefID;
8680           }
8681         nbF -= ( facesByEdge[ i ] == theUndefID );
8682       }
8683
8684     if ( nbF > 1 )
8685       return; // non-manifold
8686
8687     if ( nbF < 1 )
8688       {
8689         facesByEdge.clear();
8690       }
8691     else // nbF == 1, set a found face first
8692       {
8693         if ( facesByEdge[ 0 ] == theUndefID )
8694           {
8695             for ( size_t i = 1; i < facesByEdge.size(); ++i )
8696               if ( facesByEdge[ i ] != theUndefID )
8697                 {
8698                   facesByEdge[ 0 ] = facesByEdge[ i ];
8699                   break;
8700                 }
8701           }
8702         facesByEdge.resize( 1 );
8703       }
8704     return;
8705   }
8706
8707   //================================================================================
8708   /*!
8709    * \brief Remove a face from nodal reversed connectivity
8710    *  \param [in] node - a node of the face
8711    *  \param [in] face - the face
8712    *  \param [in.out] revNodal - reverse nodal connectivity
8713    *  \param [in,out] revNodalIndx - reverse nodal connectivity index
8714    */
8715   //================================================================================
8716
8717   void removeFromRevNodal( mcIdType node,
8718                            mcIdType face,
8719                            MCAuto<DataArrayIdType>& revNodal,
8720                            MCAuto<DataArrayIdType>& revNodalIndx)
8721   {
8722     mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8723     mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8724     auto it = std::find( fBeg, fEnd, face );
8725     if ( it != fEnd )
8726       {
8727         for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8728           *( it2 - 1 ) = *it2;
8729
8730         *( fEnd - 1 ) = theUndefID;
8731       }
8732   }
8733
8734   //================================================================================
8735   /*!
8736    * \brief Check order of two nodes in a given face
8737    *  \param [inout] n0 - node 1
8738    *  \param [inout] n1 - node 2
8739    *  \param [inout] iFEnc - face
8740    *  \param [inout] mesh - mesh
8741    *  \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8742    */
8743   //================================================================================
8744
8745   bool isReverseOrder( mcIdType n0,
8746                        mcIdType n1,
8747                        mcIdType iFEnc,
8748                        MEDCouplingUMesh* mesh[] )
8749   {
8750     int iMesh;
8751     mcIdType iF = decodeID( iFEnc, iMesh );
8752
8753     const mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8754     const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8755
8756     auto it0 = std::find( conn + connI[ iF ] + 1,
8757                           conn + connI[ iF + 1 ],
8758                           n0 );
8759     auto it1 = std::find( conn + connI[ iF ] + 1,
8760                           conn + connI[ iF + 1 ],
8761                           n1 );
8762     long i0 = it0 - conn;
8763     long i1 = it1 - conn;
8764
8765     bool isRev = ( std::abs( i1 - i0 ) == 1 ) ?  i1 < i0 :  i0 < i1;
8766     return isRev;
8767   }
8768
8769   //================================================================================
8770   /*!
8771    * \brief Change orientation of a face in one of given meshes
8772    *  \param [in] iFEnc - face ID also encoding a mesh index
8773    *  \param [in,out] mesh - object and reference meshes
8774    */
8775   //================================================================================
8776
8777   void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8778   {
8779     int iMesh;
8780     mcIdType face = decodeID( iFEnc, iMesh );
8781
8782     mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8783     mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8784
8785     const INTERP_KERNEL::CellModel& cm =
8786       INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8787
8788     cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8789                               (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8790     return;
8791   }
8792 }
8793
8794 /// @endcond
8795
8796 //================================================================================
8797 /*!
8798  * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8799  *  \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8800  *              If there are no cells in \a refFaces or it is nullptr, then any face
8801  *              in \a this mesh is used as a reference
8802  *  \throw If \a this mesh is not well defined.
8803  *  \throw If \a this mesh or \refFaces are not 2D.
8804  *  \throw If \a this mesh and \refFaces do not share nodes.
8805  *  \throw If \a refFaces are not equally oriented.
8806  *  \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8807  *
8808  *  \if ENABLE_EXAMPLES
8809  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8810  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8811  *  \endif
8812  */
8813 //================================================================================
8814
8815 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8816 {
8817   checkConsistencyLight();
8818   if ( getMeshDimension() != 2 )
8819     throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8820   if ( refFaces )
8821     {
8822       refFaces->checkConsistencyLight();
8823       if ( refFaces->getMeshDimension() != 2 )
8824         throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8825       if ( getCoords() != refFaces->getCoords() )
8826         throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8827       if ( refFaces->getNumberOfCells() == 0 )
8828         refFaces = nullptr;
8829     }
8830   if ( getNumberOfCells() == 0 )
8831     return;
8832
8833   enum { _OBJ, _REF };
8834   MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8835   MCAuto<MEDCouplingUMesh> meshPtr;
8836   if ( !mesh[_REF] )
8837     {
8838       meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8839       mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8840       mesh[_REF]->allocateCells(0);
8841       mesh[_REF]->finishInsertingCells();
8842     }
8843   mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8844                                  mesh[_REF]->getNumberOfCells() };
8845   std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8846   isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8847   isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8848
8849   MCAuto<DataArrayIdType> revNodal    [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8850   MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8851   mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8852   mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8853
8854   std::vector< mcIdType > faceNodes(4);
8855   std::vector< mcIdType > facesByEdge(4), equalFaces;
8856   std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8857
8858   while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8859     {
8860       if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8861         {
8862           for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8863             if ( nbFacesToCheck[iMesh] > 0 )
8864               for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8865                 if ( !isFaceQueued[iMesh][f] )
8866                   {
8867                     faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8868                     isFaceQueued[ iMesh ][ f ] = true;
8869                     iMesh = 0;
8870                     break;
8871                   }
8872           if ( faceQueue.empty() )
8873             break;
8874         }
8875
8876       mcIdType fID = faceQueue.back();
8877       faceQueue.pop_back();
8878
8879       int iMesh, iMesh2;
8880       mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8881
8882       nbFacesToCheck[iMesh]--;
8883
8884       equalFaces.clear();
8885       faceNodes.clear();
8886       mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8887       const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8888       const int nbEdges = cm.getNumberOfSons();
8889
8890       // loop on edges of the refFace
8891       mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8892       for ( int edge = 0; edge < nbEdges; ++edge )
8893         {
8894           mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8895
8896           // get faces sharing the edge
8897           MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8898                                            facesByEdge, equalFaces );
8899
8900           if ( facesByEdge.size() > 1 )
8901             THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8902
8903           if ( facesByEdge.size() == 1 )
8904             {
8905               // compare orientation of two faces
8906               //
8907               if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8908                 {
8909                   if ( facesByEdge[0] < 0 ) // in the ref mesh
8910                     throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8911
8912                   MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8913                 }
8914               mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8915               if ( !isFaceQueued[iMesh2][face2] )
8916                 {
8917                   isFaceQueued[iMesh2][face2] = true;
8918                   faceQueue.push_back( facesByEdge[0] );
8919                 }
8920             }
8921           n0 = n1;
8922         }
8923
8924       // remove face and equalFaces from revNodal in order not to treat them again
8925       equalFaces.push_back( fID );
8926       for ( mcIdType face : equalFaces )
8927         {
8928           mcIdType f            = MEDCouplingImpl::decodeID( face, iMesh2 );
8929           const mcIdType *conn  = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8930           const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8931           mcIdType nbNodes      = connI[ f + 1 ] - connI[ f ] - 1;
8932           for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8933
8934             MEDCouplingImpl::removeFromRevNodal( *n, f,  // not to treat f again
8935                                                  revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8936         }
8937
8938     } // while() until all faces checked
8939
8940   return;
8941 }