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