Salome HOME
Merge branch 'V9_9_BR'
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1344  *             precision.
1345  */
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1347 {
1348   checkFullyDefined();
1349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352   coords->recenterForMaxPrecision(eps);
1353   //
1354   mcIdType nbOfCells=getNumberOfCells();
1355   const mcIdType *conn=_nodal_connec->getConstPointer();
1356   const mcIdType *index=_nodal_connec_index->getConstPointer();
1357   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358   connINew->alloc(nbOfCells+1,1);
1359   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1363   bool changed=false;
1364   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1365     {
1366       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1367         {
1368           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1369           changed=true;
1370         }
1371       else
1372         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373       *connINewPtr=connNew->getNumberOfTuples();
1374     }
1375   if(changed)
1376     setConnectivity(connNew,connINew,false);
1377 }
1378
1379 /*!
1380  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382  * the format of the returned DataArrayIdType instance.
1383  *
1384  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1386  */
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1388 {
1389   checkConnectivityFullyDefined();
1390   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392   std::vector<bool> retS(maxElt,false);
1393   computeNodeIdsAlg(retS);
1394   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1395 }
1396
1397 /*!
1398  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1400  */
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1402 {
1403   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404            nbOfCells=getNumberOfCells();
1405   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406   for(mcIdType i=0;i<nbOfCells;i++)
1407     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1408       if(conn[j]>=0)
1409         {
1410           if(conn[j]<nbOfNodes)
1411             nodeIdsInUse[conn[j]]=true;
1412           else
1413             {
1414               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1415               throw INTERP_KERNEL::Exception(oss.str());
1416             }
1417         }
1418 }
1419
1420 /// @cond INTERNAL
1421
1422 struct MEDCouplingAccVisit
1423 {
1424   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426   mcIdType _new_nb_of_nodes;
1427 };
1428
1429 /// @endcond
1430
1431 /*!
1432  * Finds nodes not used in any cell and returns an array giving a new id to every node
1433  * by excluding the unused nodes, for which the array holds -1. The result array is
1434  * a mapping in "Old to New" mode.
1435  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438  *          if the node is unused or a new id else. The caller is to delete this
1439  *          array using decrRef() as it is no more needed.
1440  *  \throw If the coordinates array is not set.
1441  *  \throw If the nodal connectivity of cells is not defined.
1442  *  \throw If the nodal connectivity includes an invalid id.
1443  *
1444  *  \if ENABLE_EXAMPLES
1445  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1447  *  \endif
1448  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1449  */
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1451 {
1452   nbrOfNodesInUse=-1;
1453   mcIdType nbOfNodes(getNumberOfNodes());
1454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455   ret->alloc(nbOfNodes,1);
1456   mcIdType *traducer=ret->getPointer();
1457   std::fill(traducer,traducer+nbOfNodes,-1);
1458   mcIdType nbOfCells=getNumberOfCells();
1459   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460   const mcIdType *conn=_nodal_connec->getConstPointer();
1461   for(mcIdType i=0;i<nbOfCells;i++)
1462     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1463       if(conn[j]>=0)
1464         {
1465           if(conn[j]<nbOfNodes)
1466             traducer[conn[j]]=1;
1467           else
1468             {
1469               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1470               throw INTERP_KERNEL::Exception(oss.str());
1471             }
1472         }
1473   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1475   return ret.retn();
1476 }
1477
1478 /*!
1479  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480  * For each cell in \b this the number of nodes constituting cell is computed.
1481  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482  * So for pohyhedrons some nodes can be counted several times in the returned result.
1483  *
1484  * \return a newly allocated array
1485  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1486  */
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1488 {
1489   checkConnectivityFullyDefined();
1490   mcIdType nbOfCells=getNumberOfCells();
1491   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492   ret->alloc(nbOfCells,1);
1493   mcIdType *retPtr=ret->getPointer();
1494   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1497     {
1498       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499         *retPtr=connI[i+1]-connI[i]-1;
1500       else
1501         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1502     }
1503   return ret.retn();
1504 }
1505
1506 /*!
1507  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1509  *
1510  * \return DataArrayIdType * - new object to be deallocated by the caller.
1511  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1512  */
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1514 {
1515   checkConnectivityFullyDefined();
1516   mcIdType nbOfCells=getNumberOfCells();
1517   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518   ret->alloc(nbOfCells,1);
1519   mcIdType *retPtr=ret->getPointer();
1520   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1523     {
1524       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526         *retPtr=ToIdType(s.size());
1527       else
1528         {
1529           s.erase(-1);
1530           *retPtr=ToIdType(s.size());
1531         }
1532     }
1533   return ret.retn();
1534 }
1535
1536 /*!
1537  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1539  *
1540  * \return a newly allocated array
1541  */
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1543 {
1544   checkConnectivityFullyDefined();
1545   mcIdType nbOfCells=getNumberOfCells();
1546   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547   ret->alloc(nbOfCells,1);
1548   mcIdType *retPtr=ret->getPointer();
1549   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1552     {
1553       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1555     }
1556   return ret.retn();
1557 }
1558
1559 /*!
1560  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562  * array mean that the corresponding old node is no more used.
1563  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564  *           this->getNumberOfNodes() before call of this method. The caller is to
1565  *           delete this array using decrRef() as it is no more needed.
1566  *  \throw If the coordinates array is not set.
1567  *  \throw If the nodal connectivity of cells is not defined.
1568  *  \throw If the nodal connectivity includes an invalid id.
1569  *  \sa areAllNodesFetched
1570  *
1571  *  \if ENABLE_EXAMPLES
1572  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1574  *  \endif
1575  */
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1577 {
1578   return MEDCouplingPointSet::zipCoordsTraducer();
1579 }
1580
1581 /*!
1582  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1584  */
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1586 {
1587   switch(compType)
1588   {
1589     case 0:
1590       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1591     case 1:
1592       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1593     case 2:
1594       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1595     case 3:
1596       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1597     case 7:
1598       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1599   }
1600   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1610   return 0;
1611 }
1612
1613 /*!
1614  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1615  */
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1617 {
1618   mcIdType sz=connI[cell1+1]-connI[cell1];
1619   if(sz==connI[cell2+1]-connI[cell2])
1620     {
1621       if(conn[connI[cell1]]==conn[connI[cell2]])
1622         {
1623           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624           unsigned dim=cm.getDimension();
1625           if(dim!=3)
1626             {
1627               if(dim!=1)
1628                 {
1629                   mcIdType sz1=2*(sz-1);
1630                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634                   return work!=tmp+sz1?1:0;
1635                 }
1636               else
1637                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1638             }
1639           else
1640             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1641         }
1642     }
1643   return 0;
1644 }
1645
1646 /*!
1647  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1648  */
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1650 {
1651   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1652     {
1653       if(conn[connI[cell1]]==conn[connI[cell2]])
1654         {
1655           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1657           return s1==s2?1:0;
1658         }
1659     }
1660   return 0;
1661 }
1662
1663 /*!
1664  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1665  */
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1667 {
1668   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1669     {
1670       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1672       return s1==s2?1:0;
1673     }
1674   return 0;
1675 }
1676
1677 /*!
1678  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1679  */
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1681 {
1682   mcIdType sz=connI[cell1+1]-connI[cell1];
1683   if(sz==connI[cell2+1]-connI[cell2])
1684     {
1685       if(conn[connI[cell1]]==conn[connI[cell2]])
1686         {
1687           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688           unsigned dim=cm.getDimension();
1689           if(dim!=3)
1690             {
1691               if(dim!=1)
1692                 {
1693                   mcIdType sz1=2*(sz-1);
1694                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1698                   if(work!=tmp+sz1)
1699                     return 1;
1700                   else
1701                     {
1702                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1705                         return 2;
1706                       else
1707                         return 0;
1708                     }
1709                 }
1710               else
1711                 {//case of SEG2 and SEG3
1712                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1713                     return 1;
1714                   if(!cm.isQuadratic())
1715                     {
1716                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1719                         return 2;
1720                       return 0;
1721                     }
1722                   else
1723                     {
1724                       if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1725                         return 2;
1726                       return 0;
1727                     }
1728                 }
1729             }
1730           else
1731             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 /*!
1739  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741  * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743  * This method is time consuming.
1744  *
1745  * \param [in] compType input specifying the technique used to compare cells each other.
1746  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750  * can be used for users not sensitive to orientation of cell
1751  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1754  *
1755  */
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1757 {
1758   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759   getReverseNodalConnectivity(revNodal,revNodalI);
1760   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1761 }
1762
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1765 {
1766   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771   std::vector<bool> isFetched(nbOfCells,false);
1772   if(startCellId==0)
1773     {
1774       for(mcIdType i=startCellId;i<nbOfCells;i++)
1775         {
1776           if(!isFetched[i])
1777             {
1778               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779               std::vector<mcIdType> v,v2;
1780               if(connOfNode!=connPtr+connIPtr[i+1])
1781                 {
1782                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1784                   connOfNode++;
1785                 }
1786               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1787                 if(*connOfNode>=0)
1788                   {
1789                     v=v2;
1790                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792                     v2.resize(std::distance(v2.begin(),it));
1793                   }
1794               if(v2.size()>1)
1795                 {
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType pos=commonCellsI->back();
1799                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   else
1808     {
1809       for(mcIdType i=startCellId;i<nbOfCells;i++)
1810         {
1811           if(!isFetched[i])
1812             {
1813               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815               std::vector<mcIdType> v,v2;
1816               if(connOfNode!=connPtr+connIPtr[i+1])
1817                 {
1818                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1819                   connOfNode++;
1820                 }
1821               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1822                 if(*connOfNode>=0)
1823                   {
1824                     v=v2;
1825                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826                     v2.resize(std::distance(v2.begin(),it));
1827                   }
1828               // v2 contains now candidates. Problem candidates are sorted using id rank.
1829               if(v2.size()>1)
1830                 {
1831                   if(v2[0]!=i)
1832                   {
1833                     auto it(std::find(v2.begin(),v2.end(),i));
1834                     std::swap(*v2.begin(),*it);
1835                   }
1836                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1837                     {
1838                       mcIdType newPos(commonCells->getNumberOfTuples());
1839                       mcIdType pos(commonCellsI->back());
1840                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841                       commonCellsI->pushBackSilent(newPos);
1842                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843                         isFetched[*it]=true;
1844                     }
1845                 }
1846             }
1847         }
1848     }
1849   commonCellsArr=commonCells.retn();
1850   commonCellsIArr=commonCellsI.retn();
1851 }
1852
1853 /*!
1854  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856  * than \a this->getNumberOfCells() in the returned array means that there is no
1857  * corresponding cell in \a this mesh.
1858  * It is expected that \a this and \a other meshes share the same node coordinates
1859  * array, if it is not so an exception is thrown.
1860  *  \param [in] other - the mesh to compare with.
1861  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1862  *         valid values [0,1,2], see zipConnectivityTraducer().
1863  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1865  *         values. The caller is to delete this array using
1866  *         decrRef() as it is no more needed.
1867  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1868  *         mesh.
1869  *
1870  *  \if ENABLE_EXAMPLES
1871  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1873  *  \endif
1874  *  \sa checkDeepEquivalOnSameNodesWith()
1875  *  \sa checkGeoEquivalWith()
1876  */
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1878 {
1879   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880   mcIdType nbOfCells=getNumberOfCells();
1881   static const int possibleCompType[]={0,1,2};
1882   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1883     {
1884       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1886       oss << " !";
1887       throw INTERP_KERNEL::Exception(oss.str());
1888     }
1889   //
1890   if(other->getNumberOfCells()==0)
1891   {
1892     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1893     return true;
1894   }
1895   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898   mcIdType newNbOfCells=-1;
1899   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901   mcIdType maxPart(p0->getMaxValueInArray());
1902   bool ret(maxPart==newNbOfCells-1);
1903   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904   // fill p1 array in case of presence of cells in other not in this
1905   mcIdType *pt(p1->getPointer());
1906   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1907     pt[i+1] = i+1;
1908   //
1909   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1911   arr = p2.retn();
1912   return ret;
1913 }
1914
1915 /*!
1916  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917  * This method tries to determine if \b other is fully included in \b this.
1918  * The main difference is that this method is not expected to throw exception.
1919  * This method has two outputs :
1920  *
1921  * \param other other mesh
1922  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1924  */
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1926 {
1927   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928   DataArrayIdType *commonCells=0,*commonCellsI=0;
1929   mcIdType thisNbCells=getNumberOfCells();
1930   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933   mcIdType otherNbCells=other->getNumberOfCells();
1934   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935   arr2->alloc(otherNbCells,1);
1936   arr2->fillWithZero();
1937   mcIdType *arr2Ptr=arr2->getPointer();
1938   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939   for(mcIdType i=0;i<nbOfCommon;i++)
1940     {
1941       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942       if(start<thisNbCells)
1943         {
1944           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1945             {
1946               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947               mcIdType val=std::abs(commonCellsPtr[j])-1;
1948               if(val>=thisNbCells)
1949                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1950             }
1951         }
1952     }
1953   arr2->setName(other->getName());
1954   if(arr2->presenceOfValue(0))
1955     return false;
1956   arr=arr2.retn();
1957   return true;
1958 }
1959
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1961 {
1962   if(!other)
1963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1965   if(!otherC)
1966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967   std::vector<const MEDCouplingUMesh *> ms(2);
1968   ms[0]=this;
1969   ms[1]=otherC;
1970   return MergeUMeshesOnSameCoords(ms);
1971 }
1972
1973 /*!
1974  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976  * cellIds is not given explicitly but by a range python like.
1977  *
1978  * \param start starting ID
1979  * \param end end ID (excluded)
1980  * \param step step size
1981  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982  * \return a newly allocated
1983  *
1984  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1986  */
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1988 {
1989   if(getMeshDimension()!=-1)
1990     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1991   else
1992     {
1993       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1994       if(newNbOfCells!=1)
1995         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1996       if(start!=0)
1997         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1998       incrRef();
1999       return const_cast<MEDCouplingUMesh *>(this);
2000     }
2001 }
2002
2003 /*!
2004  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005  * The result mesh shares or not the node coordinates array with \a this mesh depending
2006  * on \a keepCoords parameter.
2007  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008  *           to write this mesh to the MED file, its cells must be sorted using
2009  *           sortCellsInMEDFileFrmt().
2010  *  \param [in] begin - an array of cell ids to include to the new mesh.
2011  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2014  *         by calling zipCoords().
2015  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016  *         to delete this mesh using decrRef() as it is no more needed.
2017  *  \throw If the coordinates array is not set.
2018  *  \throw If the nodal connectivity of cells is not defined.
2019  *  \throw If any cell id in the array \a begin is not valid.
2020  *
2021  *  \if ENABLE_EXAMPLES
2022  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2024  *  \endif
2025  */
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2027 {
2028   if(getMeshDimension()!=-1)
2029     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2030   else
2031     {
2032       if(end-begin!=1)
2033         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2034       if(begin[0]!=0)
2035         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2036       incrRef();
2037       return const_cast<MEDCouplingUMesh *>(this);
2038     }
2039 }
2040
2041 /*!
2042  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2043  *
2044  * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046  * The number of cells of \b this will remain the same with this method.
2047  *
2048  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050  * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2052  */
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2054 {
2055   checkConnectivityFullyDefined();
2056   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2060     {
2061       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063       throw INTERP_KERNEL::Exception(oss.str());
2064     }
2065   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069       throw INTERP_KERNEL::Exception(oss.str());
2070     }
2071   mcIdType nbOfCells(getNumberOfCells());
2072   bool easyAssign(true);
2073   const mcIdType *connI(_nodal_connec_index->begin());
2074   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2076     {
2077       if(*it>=0 && *it<nbOfCells)
2078         {
2079           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2080         }
2081       else
2082         {
2083           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084           throw INTERP_KERNEL::Exception(oss.str());
2085         }
2086     }
2087   if(easyAssign)
2088     {
2089       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2090       computeTypes();
2091     }
2092   else
2093     {
2094       DataArrayIdType *arrOut=0,*arrIOut=0;
2095       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2096                                                arrOut,arrIOut);
2097       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098       setConnectivity(arrOut,arrIOut,true);
2099     }
2100 }
2101
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2103 {
2104   checkConnectivityFullyDefined();
2105   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2109     {
2110       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112       throw INTERP_KERNEL::Exception(oss.str());
2113     }
2114   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118       throw INTERP_KERNEL::Exception(oss.str());
2119     }
2120   mcIdType nbOfCells=getNumberOfCells();
2121   bool easyAssign=true;
2122   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2124   mcIdType it=start;
2125   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2126     {
2127       if(it>=0 && it<nbOfCells)
2128         {
2129           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2130         }
2131       else
2132         {
2133           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134           throw INTERP_KERNEL::Exception(oss.str());
2135         }
2136     }
2137   if(easyAssign)
2138     {
2139       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2140       computeTypes();
2141     }
2142   else
2143     {
2144       DataArrayIdType *arrOut=0,*arrIOut=0;
2145       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2146                                                 arrOut,arrIOut);
2147       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148       setConnectivity(arrOut,arrIOut,true);
2149     }
2150 }
2151
2152
2153 /*!
2154  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155  * this->getMeshDimension(), that bound some cells of \a this mesh.
2156  * The cells of lower dimension to include to the result mesh are selected basing on
2157  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160  * created mesh shares the node coordinates array with \a this mesh.
2161  *  \param [in] begin - the array of node ids.
2162  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164  *         array \a begin are added, else cells whose any node is in the
2165  *         array \a begin are added.
2166  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167  *         to delete this mesh using decrRef() as it is no more needed.
2168  *  \throw If the coordinates array is not set.
2169  *  \throw If the nodal connectivity of cells is not defined.
2170  *  \throw If any node id in \a begin is not valid.
2171  *
2172  *  \if ENABLE_EXAMPLES
2173  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2175  *  \endif
2176  */
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2178 {
2179   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2184 }
2185
2186 /*!
2187  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2191  *         by calling zipCoords().
2192  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193  *         to delete this mesh using decrRef() as it is no more needed.
2194  *  \throw If the coordinates array is not set.
2195  *  \throw If the nodal connectivity of cells is not defined.
2196  *
2197  *  \if ENABLE_EXAMPLES
2198  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2200  *  \endif
2201  */
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2203 {
2204   DataArrayIdType *desc=DataArrayIdType::New();
2205   DataArrayIdType *descIndx=DataArrayIdType::New();
2206   DataArrayIdType *revDesc=DataArrayIdType::New();
2207   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2208   //
2209   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2210   revDesc->decrRef();
2211   desc->decrRef();
2212   descIndx->decrRef();
2213   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215   std::vector<mcIdType> boundaryCells;
2216   for(mcIdType i=0;i<nbOfCells;i++)
2217     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218       boundaryCells.push_back(i);
2219   revDescIndx->decrRef();
2220   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2221   return ret;
2222 }
2223
2224 /*!
2225  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2228  */
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2230 {
2231   checkFullyDefined();
2232   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2236   //
2237   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2239   //
2240   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242   const mcIdType *revDescPtr=revDesc->getConstPointer();
2243   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244   mcIdType nbOfCells=getNumberOfCells();
2245   std::vector<bool> ret1(nbOfCells,false);
2246   mcIdType sz=0;
2247   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2250   //
2251   DataArrayIdType *ret2=DataArrayIdType::New();
2252   ret2->alloc(sz,1);
2253   mcIdType *ret2Ptr=ret2->getPointer();
2254   sz=0;
2255   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2256     if(*it)
2257       *ret2Ptr++=sz;
2258   ret2->setName("BoundaryCells");
2259   return ret2;
2260 }
2261
2262 /*!
2263  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2267  *
2268  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269  * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2270  * equals a cell in \b otherDimM1OnSameCoords.
2271  *
2272  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2274  *
2275  * \param [in] otherDimM1OnSameCoords other mesh
2276  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277  * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2278  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2279  */
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2281 {
2282   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284   checkConnectivityFullyDefined();
2285   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294   DataArrayIdType *idsOtherInConsti=0;
2295   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2297   if(!b)
2298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299   std::set<mcIdType> s1;
2300   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303   s1arr_renum1->sort();
2304   cellIdsRk0=s0arr.retn();
2305   //cellIdsRk1=s_renum1.retn();
2306   cellIdsRk1=s1arr_renum1.retn();
2307 }
2308
2309 /*!
2310  * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2311  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2312  *
2313  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2314  */
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2316 {
2317   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2321   //
2322   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323   revDesc=0; desc=0; descIndx=0;
2324   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2327 }
2328
2329 /*!
2330  * Finds nodes lying on the boundary of \a this mesh.
2331  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332  *          nodes. The caller is to delete this array using decrRef() as it is no
2333  *          more needed.
2334  *  \throw If the coordinates array is not set.
2335  *  \throw If the nodal connectivity of cells is node defined.
2336  *
2337  *  \if ENABLE_EXAMPLES
2338  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2340  *  \endif
2341  */
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2343 {
2344   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345   return skin->computeFetchedNodeIds();
2346 }
2347
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2349 {
2350   incrRef();
2351   return const_cast<MEDCouplingUMesh *>(this);
2352 }
2353
2354 /*!
2355  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2358  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2359  * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2360  *
2361  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2362  *             parameter is altered during the call.
2363  * \return node ids which need to be duplicated following the algorithm explained above.
2364  *
2365  */
2366 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords) const
2367 {
2368   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2369   // which mimicks the C++
2370   using DAInt = MCAuto<DataArrayIdType>;
2371   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2372
2373   checkFullyDefined();
2374   otherDimM1OnSameCoords.checkFullyDefined();
2375   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2376     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2377   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2378     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2379
2380   // Checking star-shaped M1 group:
2381   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2382   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2383   DAInt dsi = rdit0->deltaShiftIndex();
2384   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);  // for 2D: if a point is connected to more than 2 segs. For 3D: if a seg is connected to more than two faces.
2385   if(idsTmp0->getNumberOfTuples())
2386     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2387   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2388
2389   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2390   // ie nodes belonging to the boundary "cells" (might be points) of M1
2391   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2392   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2393   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2394   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2395   dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2396   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2397   dsi = rdit0->deltaShiftIndex();  rdit0=0;
2398   DAInt boundSegs = dsi->findIdsEqual(1);  dsi = 0; // boundary segs/faces of the M0 mesh
2399   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2400   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2401   // In 3D, some points on the boundary of M0 will NOT be duplicated (where as in 2D, points on the boundary of M0 are always duplicated)
2402   // Think of a partial (plane) crack in a cube: the points at the tip of the crack and not located inside the volume of the cube are not duplicated
2403   // although they are technically on the skin of the cube.
2404   DAInt notDup = 0;
2405   if (getMeshDimension() == 3)
2406     {
2407       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2408       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2409       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2410       DataArrayIdType * corresp=0;
2411       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2412       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2413       // In the cube example above, this is a U shape polyline.
2414       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2415       corresp->decrRef();
2416       if (validIds->getNumberOfTuples())
2417         {
2418           // Build the set of segments which are: in the desc mesh of the skin of the 3D mesh (M0) **and** in the desc mesh of the M1 group:
2419           // (the U-shaped polyline described above)
2420           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2421           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2422           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2423           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2424
2425           // Specific logic to handle singular points :
2426           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2427           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2428           //   algorithm would be duplicating too much ...
2429           // This is a costly algorithm so only go into it if a simple (non sufficient) criteria is met: a node connected to more than 3 segs in meshM2:
2430           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2431           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2432           dnu1=0;dnu2=0;dnu3=0;
2433           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2434           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2435           if (singPoints->getNumberOfTuples())
2436             {
2437               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2438               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2439               // should not be duplicated
2440               //    1. Extract N D cells touching U-shape line:
2441               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2442               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2443               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2444               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2445               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2446               DataArrayIdType *idsOfM1BNt;
2447               mAroundBNDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1BNt);
2448               DAInt idsOfM1BN(idsOfM1BNt);
2449               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2450               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2451               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2452               for(const auto& v: *idsOfM1BN)
2453                 {
2454                   if (v >= nCellsDesc)    // Keep valid match only
2455                     continue;
2456                   mcIdType idx0 = revDescIBNP[v];
2457                   // Keep the two cells on either side of the face v of M1:
2458                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2459                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2460                 }
2461               //    3. Build complement
2462               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2463               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2464               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2465               DAInt inters = boundNodes->buildIntersection(nod3);
2466               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2467             }
2468           notDup = xtrem->buildSubstraction(fNodes1);
2469         }
2470       else  // if (validIds-> ...)
2471         notDup = xtrem->buildSubstraction(fNodes);
2472     }
2473   else  // if (3D ...)
2474     notDup = xtrem->buildSubstraction(fNodes);
2475
2476   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2477   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2478   return dupl.retn();
2479 }
2480
2481
2482 /*!
2483  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2484  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2485  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2486  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2487  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2488  *
2489  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2490  *             parameter is altered during the call.
2491  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2492  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2493  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2494  * \param [out] cellIdsNotModified cell ids in \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2495  *
2496  */
2497 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2498                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2499 {
2500   using DAInt = MCAuto<DataArrayIdType>;
2501   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2502
2503   checkFullyDefined();
2504   otherDimM1OnSameCoords.checkFullyDefined();
2505   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2506     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2507   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2508     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2509
2510   // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2511   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2512   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2513   mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2514   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2515   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2516   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2517   DataArrayIdType *idsOfM1t;
2518   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2519   DAInt idsOfM1Large(idsOfM1t);
2520   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2521
2522   // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2523   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2524   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2525   DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2526   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2527   DataArrayIdType *neight=0, *neighIt=0;
2528   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2529   DAInt neighL(neight), neighIL(neighIt);
2530
2531   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2532   hitCellsLarge->fillWithValue(0);  // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2533   mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2534
2535   // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2536   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2537   for(const auto& v: *idsOfM1Large)
2538     {
2539       if (v >= nL) continue;   // Keep valid match only - see doc of areCellsIncludedIn()
2540       mcIdType idx0 = revDescILP[v];
2541       // Retrieve the two cells on either side of the face v of M1:
2542       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2543       std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2544       // Handle the spread zones on the two sides of the crack:
2545       for (const auto c: {c1, c2})
2546         {
2547           if (hitCellsLargeP[c]) continue;
2548           // Identify connex zone around this cell - if we find a value already assigned there, use it.
2549           mcIdType dnu;
2550           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2551           std::set<mcIdType> sv;
2552           for (const mcIdType& s: *spreadZone)
2553             if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2554           if (sv.size() > 1)
2555             // Strange: we find in the same spread zone a +1 and -1 !
2556             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2557           // If a valid value was found, use it:
2558           mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2559           // Hopefully this does not conflict with an potential value on the other side:
2560           mcIdType other = toOther[c];
2561           if (hitCellsLargeP[other])
2562             {
2563               if(val && hitCellsLargeP[other] != -val)
2564                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflictint values - should not happen!");;
2565               // We do not yet have a value, but other side has one. Use it!
2566               if(!val) val = -hitCellsLargeP[other];
2567             }
2568           // Cover first initialisation:
2569           if (!val) val = 1;
2570           // And finally, fill the current spread zone:
2571           for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2572         }
2573     }
2574
2575   DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2576   DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2577
2578   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2579     {
2580       DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2581       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2582     }
2583   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2584   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2585   //
2586   cellIdsNeededToBeRenum=cellsRet1.retn();
2587   cellIdsNotModified=cellsRet2.retn();
2588 }
2589
2590 /*!
2591  * This method operates a modification of the connectivity and coords in \b this.
2592  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2593  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2594  * 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
2595  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2596  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2597  *
2598  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2599  *
2600  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2601  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2602  */
2603 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2604 {
2605   mcIdType nbOfNodes=getNumberOfNodes();
2606   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2607   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2608 }
2609
2610 /*!
2611  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2612  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2613  *
2614  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2615  *
2616  * \sa renumberNodesInConn
2617  */
2618 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2619 {
2620   checkConnectivityFullyDefined();
2621   mcIdType *conn(getNodalConnectivity()->getPointer());
2622   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2623   mcIdType nbOfCells=getNumberOfCells();
2624   for(mcIdType i=0;i<nbOfCells;i++)
2625     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2626       {
2627         mcIdType& node=conn[iconn];
2628         if(node>=0)//avoid polyhedron separator
2629           {
2630             node+=offset;
2631           }
2632       }
2633   _nodal_connec->declareAsNew();
2634   updateTime();
2635 }
2636
2637 /*!
2638  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2639  *  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
2640  *  of a big mesh.
2641  */
2642 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2643 {
2644   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2645 }
2646
2647 /*!
2648  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2649  *  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
2650  *  of a big mesh.
2651  */
2652 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2653 {
2654   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2655 }
2656
2657 /*!
2658  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2659  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2660  * This method is a generalization of shiftNodeNumbersInConn().
2661  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2662  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2663  *         this->getNumberOfNodes(), in "Old to New" mode.
2664  *         See \ref numbering for more info on renumbering modes.
2665  *  \throw If the nodal connectivity of cells is not defined.
2666  *
2667  *  \if ENABLE_EXAMPLES
2668  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2669  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2670  *  \endif
2671  */
2672 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2673 {
2674   checkConnectivityFullyDefined();
2675   mcIdType *conn=getNodalConnectivity()->getPointer();
2676   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2677   mcIdType nbOfCells=getNumberOfCells();
2678   for(mcIdType i=0;i<nbOfCells;i++)
2679     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2680       {
2681         mcIdType& node=conn[iconn];
2682         if(node>=0)//avoid polyhedron separator
2683           {
2684             node=newNodeNumbersO2N[node];
2685           }
2686       }
2687   _nodal_connec->declareAsNew();
2688   updateTime();
2689 }
2690
2691 /*!
2692  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2693  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2694  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2695  *
2696  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2697  */
2698 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2699 {
2700   checkConnectivityFullyDefined();
2701   mcIdType *conn=getNodalConnectivity()->getPointer();
2702   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2703   mcIdType nbOfCells=getNumberOfCells();
2704   for(mcIdType i=0;i<nbOfCells;i++)
2705     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2706       {
2707         mcIdType& node=conn[iconn];
2708         if(node>=0)//avoid polyhedron separator
2709           {
2710             node+=delta;
2711           }
2712       }
2713   _nodal_connec->declareAsNew();
2714   updateTime();
2715 }
2716
2717 /*!
2718  * This method operates a modification of the connectivity in \b this.
2719  * 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.
2720  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2721  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2722  * 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
2723  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2724  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2725  *
2726  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2727  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2728  *
2729  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2730  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2731  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2732  */
2733 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2734 {
2735   checkConnectivityFullyDefined();
2736   std::map<mcIdType,mcIdType> m;
2737   mcIdType val=offset;
2738   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2739     m[*work]=val;
2740   mcIdType *conn=getNodalConnectivity()->getPointer();
2741   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2742   mcIdType nbOfCells=getNumberOfCells();
2743   for(mcIdType i=0;i<nbOfCells;i++)
2744     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2745       {
2746         mcIdType& node=conn[iconn];
2747         if(node>=0)//avoid polyhedron separator
2748           {
2749             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2750             if(it!=m.end())
2751               node=(*it).second;
2752           }
2753       }
2754   updateTime();
2755 }
2756
2757 /*!
2758  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2759  *
2760  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2761  * After the call of this method the number of cells remains the same as before.
2762  *
2763  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2764  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2765  * be strictly in [0;this->getNumberOfCells()).
2766  *
2767  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2768  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2769  * should be contained in[0;this->getNumberOfCells()).
2770  *
2771  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2772  * \param check whether to check content of old2NewBg
2773  */
2774 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2775 {
2776   checkConnectivityFullyDefined();
2777   mcIdType nbCells=getNumberOfCells();
2778   const mcIdType *array=old2NewBg;
2779   if(check)
2780     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2781   //
2782   const mcIdType *conn=_nodal_connec->getConstPointer();
2783   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2784   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2785   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2786   const mcIdType *n2oPtr=n2o->begin();
2787   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2788   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2789   newConn->copyStringInfoFrom(*_nodal_connec);
2790   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2791   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2792   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2793   //
2794   mcIdType *newC=newConn->getPointer();
2795   mcIdType *newCI=newConnI->getPointer();
2796   mcIdType loc=0;
2797   newCI[0]=loc;
2798   for(mcIdType i=0;i<nbCells;i++)
2799     {
2800       mcIdType pos=n2oPtr[i];
2801       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2802       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2803       loc+=nbOfElts;
2804       newCI[i+1]=loc;
2805     }
2806   //
2807   setConnectivity(newConn,newConnI);
2808   if(check)
2809     free(const_cast<mcIdType *>(array));
2810 }
2811
2812 /*!
2813  * Finds cells whose bounding boxes intersect a given bounding box.
2814  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2815  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2816  *         zMax (if in 3D).
2817  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2818  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2819  *         extent of the bounding box of cell to produce an addition to this bounding box.
2820  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2821  *         cells. The caller is to delete this array using decrRef() as it is no more
2822  *         needed.
2823  *  \throw If the coordinates array is not set.
2824  *  \throw If the nodal connectivity of cells is not defined.
2825  *
2826  *  \if ENABLE_EXAMPLES
2827  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2828  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2829  *  \endif
2830  */
2831 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2832 {
2833   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2834   if(getMeshDimension()==-1)
2835     {
2836       elems->pushBackSilent(0);
2837       return elems.retn();
2838     }
2839   int dim=getSpaceDimension();
2840   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2841   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2842   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2843   const double* coords = getCoords()->getConstPointer();
2844   mcIdType nbOfCells=getNumberOfCells();
2845   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2846     {
2847       for (int i=0; i<dim; i++)
2848         {
2849           elem_bb[i*2]=std::numeric_limits<double>::max();
2850           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2851         }
2852
2853       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2854         {
2855           mcIdType node= conn[inode];
2856           if(node>=0)//avoid polyhedron separator
2857             {
2858               for (int idim=0; idim<dim; idim++)
2859                 {
2860                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2861                     {
2862                       elem_bb[idim*2] = coords[node*dim+idim] ;
2863                     }
2864                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2865                     {
2866                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2867                     }
2868                 }
2869             }
2870         }
2871       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2872         elems->pushBackSilent(ielem);
2873     }
2874   return elems.retn();
2875 }
2876
2877 /*!
2878  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2879  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2880  * added in 'elems' parameter.
2881  */
2882 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2883 {
2884   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2885   if(getMeshDimension()==-1)
2886     {
2887       elems->pushBackSilent(0);
2888       return elems.retn();
2889     }
2890   int dim=getSpaceDimension();
2891   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2892   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2893   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2894   const double* coords = getCoords()->getConstPointer();
2895   mcIdType nbOfCells=getNumberOfCells();
2896   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2897     {
2898       for (int i=0; i<dim; i++)
2899         {
2900           elem_bb[i*2]=std::numeric_limits<double>::max();
2901           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2902         }
2903
2904       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2905         {
2906           mcIdType node= conn[inode];
2907           if(node>=0)//avoid polyhedron separator
2908             {
2909               for (int idim=0; idim<dim; idim++)
2910                 {
2911                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2912                     {
2913                       elem_bb[idim*2] = coords[node*dim+idim] ;
2914                     }
2915                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2916                     {
2917                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2918                     }
2919                 }
2920             }
2921         }
2922       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2923         elems->pushBackSilent(ielem);
2924     }
2925   return elems.retn();
2926 }
2927
2928 /*!
2929  * Returns a type of a cell by its id.
2930  *  \param [in] cellId - the id of the cell of interest.
2931  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2932  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2933  */
2934 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2935 {
2936   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2937   if(cellId<_nodal_connec_index->getNbOfElems()-1)
2938     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2939   else
2940     {
2941       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2942       throw INTERP_KERNEL::Exception(oss.str());
2943     }
2944 }
2945
2946 /*!
2947  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2948  * This method does not throw exception if geometric type \a type is not in \a this.
2949  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2950  * The coordinates array is not considered here.
2951  *
2952  * \param [in] type the geometric type
2953  * \return cell ids in this having geometric type \a type.
2954  */
2955 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2956 {
2957
2958   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2959   ret->alloc(0,1);
2960   checkConnectivityFullyDefined();
2961   mcIdType nbCells=getNumberOfCells();
2962   int mdim=getMeshDimension();
2963   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2964   if(mdim!=ToIdType(cm.getDimension()))
2965     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2966   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2967   const mcIdType *pt=_nodal_connec->getConstPointer();
2968   for(mcIdType i=0;i<nbCells;i++)
2969     {
2970       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2971         ret->pushBackSilent(i);
2972     }
2973   return ret.retn();
2974 }
2975
2976 /*!
2977  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2978  */
2979 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2980 {
2981   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2982   mcIdType nbOfCells(getNumberOfCells()),ret(0);
2983   for(mcIdType i=0;i<nbOfCells;i++)
2984     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2985       ret++;
2986   return ret;
2987 }
2988
2989 /*!
2990  * Returns the nodal connectivity of a given cell.
2991  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2992  * all returned node ids can be used in getCoordinatesOfNode().
2993  *  \param [in] cellId - an id of the cell of interest.
2994  *  \param [in,out] conn - a vector where the node ids are appended. It is not
2995  *         cleared before the appending.
2996  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2997  */
2998 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2999 {
3000   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3001   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3002     if(*w>=0)
3003       conn.push_back(*w);
3004 }
3005
3006 std::string MEDCouplingUMesh::simpleRepr() const
3007 {
3008   static const char msg0[]="No coordinates specified !";
3009   std::ostringstream ret;
3010   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3011   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3012   int tmpp1,tmpp2;
3013   double tt=getTime(tmpp1,tmpp2);
3014   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3015   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3016   if(_mesh_dim>=-1)
3017     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3018   else
3019     { ret << " Mesh dimension has not been set or is invalid !"; }
3020   if(_coords!=0)
3021     {
3022       const int spaceDim=getSpaceDimension();
3023       ret << spaceDim << "\nInfo attached on space dimension : ";
3024       for(int i=0;i<spaceDim;i++)
3025         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3026       ret << "\n";
3027     }
3028   else
3029     ret << msg0 << "\n";
3030   ret << "Number of nodes : ";
3031   if(_coords!=0)
3032     ret << getNumberOfNodes() << "\n";
3033   else
3034     ret << msg0 << "\n";
3035   ret << "Number of cells : ";
3036   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3037     ret << getNumberOfCells() << "\n";
3038   else
3039     ret << "No connectivity specified !" << "\n";
3040   ret << "Cell types present : ";
3041   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3042     {
3043       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3044       ret << cm.getRepr() << " ";
3045     }
3046   ret << "\n";
3047   return ret.str();
3048 }
3049
3050 std::string MEDCouplingUMesh::advancedRepr() const
3051 {
3052   std::ostringstream ret;
3053   ret << simpleRepr();
3054   ret << "\nCoordinates array : \n___________________\n\n";
3055   if(_coords)
3056     _coords->reprWithoutNameStream(ret);
3057   else
3058     ret << "No array set !\n";
3059   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3060   reprConnectivityOfThisLL(ret);
3061   return ret.str();
3062 }
3063
3064 /*!
3065  * This method returns a C++ code that is a dump of \a this.
3066  * This method will throw if this is not fully defined.
3067  */
3068 std::string MEDCouplingUMesh::cppRepr() const
3069 {
3070   static const char coordsName[]="coords";
3071   static const char connName[]="conn";
3072   static const char connIName[]="connI";
3073   checkFullyDefined();
3074   std::ostringstream ret; ret << "// coordinates" << std::endl;
3075   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3076   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3077   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3078   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3079   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3080   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3081   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3082   return ret.str();
3083 }
3084
3085 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3086 {
3087   std::ostringstream ret;
3088   reprConnectivityOfThisLL(ret);
3089   return ret.str();
3090 }
3091
3092 /*!
3093  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3094  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3095  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3096  * some algos).
3097  *
3098  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3099  * 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
3100  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3101  */
3102 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3103 {
3104   int mdim=getMeshDimension();
3105   if(mdim<0)
3106     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3107   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3108   MCAuto<DataArrayIdType> tmp1,tmp2;
3109   bool needToCpyCT=true;
3110   if(!_nodal_connec)
3111     {
3112       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3113       needToCpyCT=false;
3114     }
3115   else
3116     {
3117       tmp1=_nodal_connec;
3118       tmp1->incrRef();
3119     }
3120   if(!_nodal_connec_index)
3121     {
3122       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3123       needToCpyCT=false;
3124     }
3125   else
3126     {
3127       tmp2=_nodal_connec_index;
3128       tmp2->incrRef();
3129     }
3130   ret->setConnectivity(tmp1,tmp2,false);
3131   if(needToCpyCT)
3132     ret->_types=_types;
3133   if(!_coords)
3134     {
3135       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3136       ret->setCoords(coords);
3137     }
3138   else
3139     ret->setCoords(_coords);
3140   return ret.retn();
3141 }
3142
3143 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3144 {
3145   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3146   const mcIdType *pt=_nodal_connec->getConstPointer();
3147   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3148     return ptI[cellId+1]-ptI[cellId]-1;
3149   else
3150     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3151 }
3152
3153 /*!
3154  * Returns types of cells of the specified part of \a this mesh.
3155  * This method avoids computing sub-mesh explicitly to get its types.
3156  *  \param [in] begin - an array of cell ids of interest.
3157  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3158  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3159  *         describing the cell types.
3160  *  \throw If the coordinates array is not set.
3161  *  \throw If the nodal connectivity of cells is not defined.
3162  *  \sa getAllGeoTypes()
3163  */
3164 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3165 {
3166   checkFullyDefined();
3167   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3168   const mcIdType *conn=_nodal_connec->getConstPointer();
3169   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3170   for(const mcIdType *w=begin;w!=end;w++)
3171     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3172   return ret;
3173 }
3174
3175 /*!
3176  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3177  * Optionally updates
3178  * a set of types of cells constituting \a this mesh.
3179  * This method is for advanced users having prepared their connectivity before. For
3180  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3181  *  \param [in] conn - the nodal connectivity array.
3182  *  \param [in] connIndex - the nodal connectivity index array.
3183  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3184  *         mesh is updated.
3185  */
3186 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3187 {
3188   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3189   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3190   if(isComputingTypes)
3191     computeTypes();
3192   declareAsNew();
3193 }
3194
3195 /*!
3196  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3197  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3198  */
3199 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3200     _nodal_connec(0),_nodal_connec_index(0),
3201     _types(other._types)
3202 {
3203   if(other._nodal_connec)
3204     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3205   if(other._nodal_connec_index)
3206     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3207 }
3208
3209 MEDCouplingUMesh::~MEDCouplingUMesh()
3210 {
3211   if(_nodal_connec)
3212     _nodal_connec->decrRef();
3213   if(_nodal_connec_index)
3214     _nodal_connec_index->decrRef();
3215 }
3216
3217 /*!
3218  * Recomputes a set of cell types of \a this mesh. For more info see
3219  * \ref MEDCouplingUMeshNodalConnectivity.
3220  */
3221 void MEDCouplingUMesh::computeTypes()
3222 {
3223   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3224 }
3225
3226
3227 /*!
3228  * Returns a number of cells constituting \a this mesh.
3229  *  \return mcIdType - the number of cells in \a this mesh.
3230  *  \throw If the nodal connectivity of cells is not defined.
3231  */
3232 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3233 {
3234   if(_nodal_connec_index)
3235     return _nodal_connec_index->getNumberOfTuples()-1;
3236   else
3237     if(_mesh_dim==-1)
3238       return 1;
3239     else
3240       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3241 }
3242
3243 /*!
3244  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3245  * mesh. For more info see \ref meshes.
3246  *  \return int - the dimension of \a this mesh.
3247  *  \throw If the mesh dimension is not defined using setMeshDimension().
3248  */
3249 int MEDCouplingUMesh::getMeshDimension() const
3250 {
3251   if(_mesh_dim<-1)
3252     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3253   return _mesh_dim;
3254 }
3255
3256 /*!
3257  * Returns a length of the nodal connectivity array.
3258  * This method is for test reason. Normally the integer returned is not useable by
3259  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3260  *  \return mcIdType - the length of the nodal connectivity array.
3261  */
3262 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3263 {
3264   return _nodal_connec->getNbOfElems();
3265 }
3266
3267 /*!
3268  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3269  */
3270 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3271 {
3272   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3273   tinyInfo.push_back(ToIdType(getMeshDimension()));
3274   tinyInfo.push_back(getNumberOfCells());
3275   if(_nodal_connec)
3276     tinyInfo.push_back(getNodalConnectivityArrayLen());
3277   else
3278     tinyInfo.push_back(-1);
3279 }
3280
3281 /*!
3282  * First step of unserialization process.
3283  */
3284 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3285 {
3286   return tinyInfo[6]<=0;
3287 }
3288
3289 /*!
3290  * Second step of serialization process.
3291  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3292  * \param a1 DataArrayDouble
3293  * \param a2 DataArrayDouble
3294  * \param littleStrings string vector
3295  */
3296 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3297 {
3298   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3299   if(tinyInfo[5]!=-1)
3300     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3301 }
3302
3303 /*!
3304  * Third and final step of serialization process.
3305  */
3306 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3307 {
3308   MEDCouplingPointSet::serialize(a1,a2);
3309   if(getMeshDimension()>-1)
3310     {
3311       a1=DataArrayIdType::New();
3312       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3313       mcIdType *ptA1=a1->getPointer();
3314       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3315       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3316       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3317       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3318     }
3319   else
3320     a1=0;
3321 }
3322
3323 /*!
3324  * Second and final unserialization process.
3325  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3326  */
3327 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3328 {
3329   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3330   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3331   if(tinyInfo[7]!=-1)
3332     {
3333       // Connectivity
3334       const mcIdType *recvBuffer=a1->getConstPointer();
3335       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3336       myConnecIndex->alloc(tinyInfo[6]+1,1);
3337       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3338       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3339       myConnec->alloc(tinyInfo[7],1);
3340       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3341       setConnectivity(myConnec, myConnecIndex);
3342     }
3343 }
3344
3345
3346
3347 /*!
3348  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3349  * mesh.<br>
3350  * For 1D cells, the returned field contains lengths.<br>
3351  * For 2D cells, the returned field contains areas.<br>
3352  * For 3D cells, the returned field contains volumes.
3353  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3354  *         orientation, i.e. the volume is always positive.
3355  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3356  *         and one time . The caller is to delete this field using decrRef() as it is no
3357  *         more needed.
3358  */
3359 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3360 {
3361   std::string name="MeasureOfMesh_";
3362   name+=getName();
3363   mcIdType nbelem=getNumberOfCells();
3364   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3365   field->setName(name);
3366   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3367   array->alloc(nbelem,1);
3368   double *area_vol=array->getPointer();
3369   field->setArray(array) ; array=0;
3370   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3371   field->synchronizeTimeWithMesh();
3372   if(getMeshDimension()!=-1)
3373     {
3374       mcIdType ipt;
3375       INTERP_KERNEL::NormalizedCellType type;
3376       int dim_space=getSpaceDimension();
3377       const double *coords=getCoords()->getConstPointer();
3378       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3379       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3380       for(mcIdType iel=0;iel<nbelem;iel++)
3381         {
3382           ipt=connec_index[iel];
3383           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3384           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);
3385         }
3386       if(isAbs)
3387         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3388     }
3389   else
3390     {
3391       area_vol[0]=std::numeric_limits<double>::max();
3392     }
3393   return field.retn();
3394 }
3395
3396 /*!
3397  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3398  * mesh.<br>
3399  * For 1D cells, the returned array contains lengths.<br>
3400  * For 2D cells, the returned array contains areas.<br>
3401  * For 3D cells, the returned array contains volumes.
3402  * This method avoids building explicitly a part of \a this mesh to perform the work.
3403  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3404  *         orientation, i.e. the volume is always positive.
3405  *  \param [in] begin - an array of cell ids of interest.
3406  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3407  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3408  *          delete this array using decrRef() as it is no more needed.
3409  *
3410  *  \if ENABLE_EXAMPLES
3411  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3412  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3413  *  \endif
3414  *  \sa getMeasureField()
3415  */
3416 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3417 {
3418   std::string name="PartMeasureOfMesh_";
3419   name+=getName();
3420   std::size_t nbelem=std::distance(begin,end);
3421   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3422   array->setName(name);
3423   array->alloc(nbelem,1);
3424   double *area_vol=array->getPointer();
3425   if(getMeshDimension()!=-1)
3426     {
3427       mcIdType ipt;
3428       INTERP_KERNEL::NormalizedCellType type;
3429       int dim_space=getSpaceDimension();
3430       const double *coords=getCoords()->getConstPointer();
3431       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3432       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3433       for(const mcIdType *iel=begin;iel!=end;iel++)
3434         {
3435           ipt=connec_index[*iel];
3436           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3437           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3438         }
3439       if(isAbs)
3440         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3441     }
3442   else
3443     {
3444       area_vol[0]=std::numeric_limits<double>::max();
3445     }
3446   return array.retn();
3447 }
3448
3449 /*!
3450  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3451  * \a this one. The returned field contains the dual cell volume for each corresponding
3452  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3453  *  the dual mesh in P1 sens of \a this.<br>
3454  * For 1D cells, the returned field contains lengths.<br>
3455  * For 2D cells, the returned field contains areas.<br>
3456  * For 3D cells, the returned field contains volumes.
3457  * This method is useful to check "P1*" conservative interpolators.
3458  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3459  *         orientation, i.e. the volume is always positive.
3460  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3461  *          nodes and one time. The caller is to delete this array using decrRef() as
3462  *          it is no more needed.
3463  */
3464 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3465 {
3466   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3467   std::string name="MeasureOnNodeOfMesh_";
3468   name+=getName();
3469   mcIdType nbNodes=getNumberOfNodes();
3470   MCAuto<DataArrayDouble> nnpc;
3471   {
3472     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3473     nnpc=tmp2->convertToDblArr();
3474   }
3475   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3476   const double *nnpcPtr(nnpc->begin());
3477   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3478   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3479   array->alloc(nbNodes,1);
3480   double *valsToFill=array->getPointer();
3481   std::fill(valsToFill,valsToFill+nbNodes,0.);
3482   const double *values=tmp->getArray()->getConstPointer();
3483   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3484   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3485   getReverseNodalConnectivity(da,daInd);
3486   const mcIdType *daPtr=da->getConstPointer();
3487   const mcIdType *daIPtr=daInd->getConstPointer();
3488   for(mcIdType i=0;i<nbNodes;i++)
3489     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3490       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3491   ret->setMesh(this);
3492   ret->setArray(array);
3493   return ret.retn();
3494 }
3495
3496 /*!
3497  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3498  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3499  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3500  * and are normalized.
3501  * <br> \a this can be either
3502  * - a  2D mesh in 2D or 3D space or
3503  * - an 1D mesh in 2D space.
3504  *
3505  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3506  *          cells and one time. The caller is to delete this field using decrRef() as
3507  *          it is no more needed.
3508  *  \throw If the nodal connectivity of cells is not defined.
3509  *  \throw If the coordinates array is not set.
3510  *  \throw If the mesh dimension is not set.
3511  *  \throw If the mesh and space dimension is not as specified above.
3512  */
3513 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3514 {
3515   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3516     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3517   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3518   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3519   mcIdType nbOfCells=getNumberOfCells();
3520   int nbComp=getMeshDimension()+1;
3521   array->alloc(nbOfCells,nbComp);
3522   double *vals=array->getPointer();
3523   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3524   const mcIdType *conn=_nodal_connec->getConstPointer();
3525   const double *coords=_coords->getConstPointer();
3526   if(getMeshDimension()==2)
3527     {
3528       if(getSpaceDimension()==3)
3529         {
3530           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3531           const double *locPtr=loc->getConstPointer();
3532           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3533             {
3534               mcIdType offset=connI[i];
3535               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3536               double n=INTERP_KERNEL::norm<3>(vals);
3537               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3538             }
3539         }
3540       else
3541         {
3542           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3543           const double *isAbsPtr=isAbs->getArray()->begin();
3544           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3545             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3546         }
3547     }
3548   else//meshdimension==1
3549     {
3550       double tmp[2];
3551       for(mcIdType i=0;i<nbOfCells;i++)
3552         {
3553           mcIdType offset=connI[i];
3554           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3555           double n=INTERP_KERNEL::norm<2>(tmp);
3556           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3557           *vals++=-tmp[1];
3558           *vals++=tmp[0];
3559         }
3560     }
3561   ret->setArray(array);
3562   ret->setMesh(this);
3563   ret->synchronizeTimeWithSupport();
3564   return ret.retn();
3565 }
3566
3567 /*!
3568  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3569  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3570  * and are normalized.
3571  * <br> \a this can be either
3572  * - a  2D mesh in 2D or 3D space or
3573  * - an 1D mesh in 2D space.
3574  *
3575  * This method avoids building explicitly a part of \a this mesh to perform the work.
3576  *  \param [in] begin - an array of cell ids of interest.
3577  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3578  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3579  *          cells and one time. The caller is to delete this field using decrRef() as
3580  *          it is no more needed.
3581  *  \throw If the nodal connectivity of cells is not defined.
3582  *  \throw If the coordinates array is not set.
3583  *  \throw If the mesh dimension is not set.
3584  *  \throw If the mesh and space dimension is not as specified above.
3585  *  \sa buildOrthogonalField()
3586  *
3587  *  \if ENABLE_EXAMPLES
3588  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3589  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3590  *  \endif
3591  */
3592 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3593 {
3594   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3595     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3596   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3597   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3598   std::size_t nbelems=std::distance(begin,end);
3599   int nbComp=getMeshDimension()+1;
3600   array->alloc(nbelems,nbComp);
3601   double *vals=array->getPointer();
3602   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3603   const mcIdType *conn=_nodal_connec->getConstPointer();
3604   const double *coords=_coords->getConstPointer();
3605   if(getMeshDimension()==2)
3606     {
3607       if(getSpaceDimension()==3)
3608         {
3609           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3610           const double *locPtr=loc->getConstPointer();
3611           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3612             {
3613               mcIdType offset=connI[*i];
3614               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3615               double n=INTERP_KERNEL::norm<3>(vals);
3616               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3617             }
3618         }
3619       else
3620         {
3621           for(std::size_t i=0;i<nbelems;i++)
3622             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3623         }
3624     }
3625   else//meshdimension==1
3626     {
3627       double tmp[2];
3628       for(const mcIdType *i=begin;i!=end;i++)
3629         {
3630           mcIdType offset=connI[*i];
3631           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3632           double n=INTERP_KERNEL::norm<2>(tmp);
3633           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3634           *vals++=-tmp[1];
3635           *vals++=tmp[0];
3636         }
3637     }
3638   ret->setArray(array);
3639   ret->setMesh(this);
3640   ret->synchronizeTimeWithSupport();
3641   return ret.retn();
3642 }
3643
3644 /*!
3645  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3646  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3647  * and are \b not normalized.
3648  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3649  *          cells and one time. The caller is to delete this field using decrRef() as
3650  *          it is no more needed.
3651  *  \throw If the nodal connectivity of cells is not defined.
3652  *  \throw If the coordinates array is not set.
3653  *  \throw If \a this->getMeshDimension() != 1.
3654  *  \throw If \a this mesh includes cells of type other than SEG2.
3655  */
3656 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3657 {
3658   if(getMeshDimension()!=1)
3659     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3660   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3661     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3662   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3663   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3664   mcIdType nbOfCells=getNumberOfCells();
3665   int spaceDim=getSpaceDimension();
3666   array->alloc(nbOfCells,spaceDim);
3667   double *pt=array->getPointer();
3668   const double *coo=getCoords()->getConstPointer();
3669   std::vector<mcIdType> conn;
3670   conn.reserve(2);
3671   for(mcIdType i=0;i<nbOfCells;i++)
3672     {
3673       conn.resize(0);
3674       getNodeIdsOfCell(i,conn);
3675       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3676     }
3677   ret->setArray(array);
3678   ret->setMesh(this);
3679   ret->synchronizeTimeWithSupport();
3680   return ret.retn();
3681 }
3682
3683 /*!
3684  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3685  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3686  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3687  * from. If a result face is shared by two 3D cells, then the face in included twice in
3688  * the result mesh.
3689  *  \param [in] origin - 3 components of a point defining location of the plane.
3690  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3691  *         must be greater than 1e-6.
3692  *  \param [in] eps - half-thickness of the plane.
3693  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3694  *         producing correspondent 2D cells. The caller is to delete this array
3695  *         using decrRef() as it is no more needed.
3696  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3697  *         not share the node coordinates array with \a this mesh. The caller is to
3698  *         delete this mesh using decrRef() as it is no more needed.
3699  *  \throw If the coordinates array is not set.
3700  *  \throw If the nodal connectivity of cells is not defined.
3701  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3702  *  \throw If magnitude of \a vec is less than 1e-6.
3703  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3704  *  \throw If \a this includes quadratic cells.
3705  */
3706 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3707 {
3708   checkFullyDefined();
3709   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3710     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3711   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3712   if(candidates->empty())
3713     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3714   std::vector<mcIdType> nodes;
3715   DataArrayIdType *cellIds1D=0;
3716   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3717   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3718   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3719   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3720   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3721   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3722   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3723   revDesc2=0; revDescIndx2=0;
3724   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3725   revDesc1=0; revDescIndx1=0;
3726   //Marking all 1D cells that contained at least one node located on the plane
3727   //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3728   //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3729   //due to accuracy errors when the needed nodes already exist)
3730   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3731   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3732   //
3733   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3734   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3735     cut3DCurve[*it]=-1;
3736   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3737   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3738   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3739                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3740                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3741   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3742   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3743   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3744   if(cellIds2->empty())
3745     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3746   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3747   ret->setCoords(mDesc1->getCoords());
3748   ret->setConnectivity(conn,connI,true);
3749   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3750   return ret.retn();
3751 }
3752
3753 /*!
3754  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3755 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
3756 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3757 the result mesh.
3758  *  \param [in] origin - 3 components of a point defining location of the plane.
3759  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3760  *         must be greater than 1e-6.
3761  *  \param [in] eps - half-thickness of the plane.
3762  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3763  *         producing correspondent segments. The caller is to delete this array
3764  *         using decrRef() as it is no more needed.
3765  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3766  *         mesh in 3D space. This mesh does not share the node coordinates array with
3767  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3768  *         no more needed.
3769  *  \throw If the coordinates array is not set.
3770  *  \throw If the nodal connectivity of cells is not defined.
3771  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3772  *  \throw If magnitude of \a vec is less than 1e-6.
3773  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3774  *  \throw If \a this includes quadratic cells.
3775  */
3776 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3777 {
3778   checkFullyDefined();
3779   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3780     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3781   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3782   if(candidates->empty())
3783     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3784   std::vector<mcIdType> nodes;
3785   DataArrayIdType *cellIds1D(0);
3786   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3787   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3788   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3789   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3790   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3791   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3792   //
3793   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3794   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3795     cut3DCurve[*it]=-1;
3796   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3797   mcIdType ncellsSub=subMesh->getNumberOfCells();
3798   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3799   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3800                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3801                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3802   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3803   conn->alloc(0,1);
3804   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3805   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3806   for(mcIdType i=0;i<ncellsSub;i++)
3807     {
3808       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3809         {
3810           if(cut3DSurf[i].first!=-2)
3811             {
3812               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3813               connI->pushBackSilent(conn->getNumberOfTuples());
3814               cellIds2->pushBackSilent(i);
3815             }
3816           else
3817             {
3818               mcIdType cellId3DSurf=cut3DSurf[i].second;
3819               mcIdType offset=nodalI[cellId3DSurf]+1;
3820               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3821               for(mcIdType j=0;j<nbOfEdges;j++)
3822                 {
3823                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3824                   connI->pushBackSilent(conn->getNumberOfTuples());
3825                   cellIds2->pushBackSilent(cellId3DSurf);
3826                 }
3827             }
3828         }
3829     }
3830   if(cellIds2->empty())
3831     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3832   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3833   ret->setCoords(mDesc1->getCoords());
3834   ret->setConnectivity(conn,connI,true);
3835   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3836   return ret.retn();
3837 }
3838
3839 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3840 {
3841   checkFullyDefined();
3842   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3843     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3844   if(getNumberOfCells()!=1)
3845     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3846   //
3847   std::vector<mcIdType> nodes;
3848   findNodesOnPlane(origin,vec,eps,nodes);
3849   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());
3850   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3851   revDesc2=0; revDescIndx2=0;
3852   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3853   revDesc1=0; revDescIndx1=0;
3854   DataArrayIdType *cellIds1D(0);
3855   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3856   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3857   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3858   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3859     cut3DCurve[*it]=-1;
3860   bool sameNbNodes;
3861   {
3862     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3863     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3864     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3865   }
3866   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3867   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3868                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3869                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3870   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3871   connI->pushBackSilent(0); conn->alloc(0,1);
3872   {
3873     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3874     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3875     if(cellIds2->empty())
3876       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3877   }
3878   std::vector<std::vector<mcIdType> > res;
3879   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3880   std::size_t sz(res.size());
3881   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3883   for(std::size_t i=0;i<sz;i++)
3884     {
3885       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3886       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3887       connI->pushBackSilent(conn->getNumberOfTuples());
3888     }
3889   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3890   ret->setCoords(mDesc1->getCoords());
3891   ret->setConnectivity(conn,connI,true);
3892   mcIdType nbCellsRet(ret->getNumberOfCells());
3893   //
3894   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3895   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3896   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3897   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3898   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3899   MCAuto<DataArrayDouble> occm;
3900   {
3901     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3902     occm=DataArrayDouble::Substract(ccm,pt);
3903   }
3904   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3905   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);
3906   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3907   //
3908   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3909   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3910   ret2->setCoords(mDesc1->getCoords());
3911   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3912   conn2I->pushBackSilent(0); conn2->alloc(0,1);
3913   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3914   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3915   if(dott->getIJ(0,0)>0)
3916     {
3917       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3918       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3919     }
3920   else
3921     {
3922       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3923       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3924     }
3925   for(mcIdType i=1;i<nbCellsRet;i++)
3926     {
3927       if(dott2->getIJ(i,0)<0)
3928         {
3929           if(ciPtr[i+1]-ciPtr[i]>=4)
3930             {
3931               cell0.push_back(-1);
3932               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3933             }
3934         }
3935       else
3936         {
3937           if(ciPtr[i+1]-ciPtr[i]>=4)
3938             {
3939               cell1.push_back(-1);
3940               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3941             }
3942         }
3943     }
3944   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3945   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3946   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3947   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3948   ret2->setConnectivity(conn2,conn2I,true);
3949   ret2->checkConsistencyLight();
3950   ret2->orientCorrectlyPolyhedrons();
3951   return ret2;
3952 }
3953
3954 /*!
3955  * Finds cells whose bounding boxes intersect a given plane.
3956  *  \param [in] origin - 3 components of a point defining location of the plane.
3957  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3958  *         must be greater than 1e-6.
3959  *  \param [in] eps - half-thickness of the plane.
3960  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3961  *         cells. The caller is to delete this array using decrRef() as it is no more
3962  *         needed.
3963  *  \throw If the coordinates array is not set.
3964  *  \throw If the nodal connectivity of cells is not defined.
3965  *  \throw If \a this->getSpaceDimension() != 3.
3966  *  \throw If magnitude of \a vec is less than 1e-6.
3967  *  \sa buildSlice3D()
3968  */
3969 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3970 {
3971   checkFullyDefined();
3972   if(getSpaceDimension()!=3)
3973     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3974   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3975   if(normm<1e-6)
3976     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3977   double vec2[3];
3978   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3979   double angle=acos(vec[2]/normm);
3980   MCAuto<DataArrayIdType> cellIds;
3981   double bbox[6];
3982   if(angle>eps)
3983     {
3984       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3985       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3986       if(normm2/normm>1e-6)
3987         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3988       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3989       mw->setCoords(coo);
3990       mw->getBoundingBox(bbox);
3991       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3992       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3993     }
3994   else
3995     {
3996       getBoundingBox(bbox);
3997       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3998       cellIds=getCellsInBoundingBox(bbox,eps);
3999     }
4000   return cellIds.retn();
4001 }
4002
4003 /*!
4004  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4005  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4006  * No consideration of coordinate is done by this method.
4007  * 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)
4008  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4009  */
4010 bool MEDCouplingUMesh::isContiguous1D() const
4011 {
4012   if(getMeshDimension()!=1)
4013     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4014   mcIdType nbCells=getNumberOfCells();
4015   if(nbCells<1)
4016     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4017   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4018   mcIdType ref=conn[connI[0]+2];
4019   for(mcIdType i=1;i<nbCells;i++)
4020     {
4021       if(conn[connI[i]+1]!=ref)
4022         return false;
4023       ref=conn[connI[i]+2];
4024     }
4025   return true;
4026 }
4027
4028 /*!
4029  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4030  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4031  * \param pt reference point of the line
4032  * \param v normalized director vector of the line
4033  * \param eps max precision before throwing an exception
4034  * \param res output of size this->getNumberOfCells
4035  */
4036 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4037 {
4038   if(getMeshDimension()!=1)
4039     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4040   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4041     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4042   if(getSpaceDimension()!=3)
4043     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4044   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4045   const double *fPtr=f->getArray()->getConstPointer();
4046   double tmp[3];
4047   for(mcIdType i=0;i<getNumberOfCells();i++)
4048     {
4049       const double *tmp1=fPtr+3*i;
4050       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4051       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4052       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4053       double n1=INTERP_KERNEL::norm<3>(tmp);
4054       n1/=INTERP_KERNEL::norm<3>(tmp1);
4055       if(n1>eps)
4056         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4057     }
4058   const double *coo=getCoords()->getConstPointer();
4059   for(mcIdType i=0;i<getNumberOfNodes();i++)
4060     {
4061       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4062       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4063       res[i]=std::accumulate(tmp,tmp+3,0.);
4064     }
4065 }
4066
4067 /*!
4068  * 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.
4069  * \a this is expected to be a mesh so that its space dimension is equal to its
4070  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4071  * 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).
4072  *
4073  * 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
4074  * 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).
4075  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4076  *
4077  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4078  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4079  *
4080  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4081  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4082  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4083  * \return the positive value of the distance.
4084  * \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
4085  * dimension - 1.
4086  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4087  */
4088 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4089 {
4090   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4091   if(meshDim!=spaceDim-1)
4092     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4093   if(meshDim!=2 && meshDim!=1)
4094     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4095   checkFullyDefined();
4096   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4097     { 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()); }
4098   DataArrayIdType *ret1=0;
4099   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4100   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4101   MCAuto<DataArrayIdType> ret1Safe(ret1);
4102   cellId=*ret1Safe->begin();
4103   return *ret0->begin();
4104 }
4105
4106 /*!
4107  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4108  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4109  * 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
4110  * 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).
4111  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4112  *
4113  * \a this is expected to be a mesh so that its space dimension is equal to its
4114  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4115  * 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).
4116  *
4117  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4118  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4119  *
4120  * \param [in] pts the list of points in which each tuple represents a point
4121  * \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.
4122  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4123  * \throw if number of components of \a pts is not equal to the space dimension.
4124  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4125  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4126  */
4127 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4128 {
4129   if(!pts)
4130     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4131   pts->checkAllocated();
4132   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4133   if(meshDim!=spaceDim-1)
4134     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4135   if(meshDim!=2 && meshDim!=1)
4136     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4137   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4138     {
4139       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4140       throw INTERP_KERNEL::Exception(oss.str());
4141     }
4142   checkFullyDefined();
4143   mcIdType nbCells=getNumberOfCells();
4144   if(nbCells==0)
4145     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4146   mcIdType nbOfPts=pts->getNumberOfTuples();
4147   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4148   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4149   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4150   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4151   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4152   const double *bbox(bboxArr->begin());
4153   switch(spaceDim)
4154   {
4155     case 3:
4156       {
4157         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4158         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4159           {
4160             double x=std::numeric_limits<double>::max();
4161             std::vector<mcIdType> elems;
4162             myTree.getMinDistanceOfMax(ptsPtr,x);
4163             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4164             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4165           }
4166         break;
4167       }
4168     case 2:
4169       {
4170         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4171         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4172           {
4173             double x=std::numeric_limits<double>::max();
4174             std::vector<mcIdType> elems;
4175             myTree.getMinDistanceOfMax(ptsPtr,x);
4176             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4177             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4178           }
4179         break;
4180       }
4181     default:
4182       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4183   }
4184   cellIds=ret1.retn();
4185   return ret0.retn();
4186 }
4187
4188 /// @cond INTERNAL
4189
4190 /// @endcond
4191
4192 /*!
4193  * Finds cells in contact with a ball (i.e. a point with precision).
4194  * 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.
4195  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4196  *
4197  * \warning This method is suitable if the caller intends to evaluate only one
4198  *          point, for more points getCellsContainingPoints() is recommended as it is
4199  *          faster.
4200  *  \param [in] pos - array of coordinates of the ball central point.
4201  *  \param [in] eps - ball radius.
4202  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4203  *         if there are no such cells.
4204  *  \throw If the coordinates array is not set.
4205  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4206  */
4207 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4208 {
4209   std::vector<mcIdType> elts;
4210   getCellsContainingPoint(pos,eps,elts);
4211   if(elts.empty())
4212     return -1;
4213   return elts.front();
4214 }
4215
4216 /*!
4217  * Finds cells in contact with a ball (i.e. a point with precision).
4218  * 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.
4219  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4220  * \warning This method is suitable if the caller intends to evaluate only one
4221  *          point, for more points getCellsContainingPoints() is recommended as it is
4222  *          faster.
4223  *  \param [in] pos - array of coordinates of the ball central point.
4224  *  \param [in] eps - ball radius.
4225  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4226  *         before inserting ids.
4227  *  \throw If the coordinates array is not set.
4228  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4229  *
4230  *  \if ENABLE_EXAMPLES
4231  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4232  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4233  *  \endif
4234  */
4235 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4236 {
4237   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4238   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4239   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4240 }
4241
4242 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4243                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4244                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4245 {
4246   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4247   if(spaceDim==3)
4248     {
4249       if(mDim==3)
4250         {
4251           const double *coords=_coords->getConstPointer();
4252           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4253         }
4254       else
4255         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4256     }
4257   else if(spaceDim==2)
4258     {
4259       if(mDim==2)
4260         {
4261           const double *coords=_coords->getConstPointer();
4262           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4263         }
4264       else
4265         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4266     }
4267   else if(spaceDim==1)
4268     {
4269       if(mDim==1)
4270         {
4271           const double *coords=_coords->getConstPointer();
4272           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4273         }
4274       else
4275         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4276     }
4277   else
4278     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4279 }
4280
4281 /*!
4282  * Finds cells in contact with several balls (i.e. points with precision).
4283  * This method is an extension of getCellContainingPoint() and
4284  * getCellsContainingPoint() for the case of multiple points.
4285  * 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.
4286  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4287  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4288  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4289  *         this->getSpaceDimension() * \a nbOfPoints
4290  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4291  *  \param [in] eps - radius of balls (i.e. the precision).
4292  *  \param [out] elts - vector returning ids of found cells.
4293  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4294  *         dividing cell ids in \a elts into groups each referring to one
4295  *         point. Its every element (except the last one) is an index pointing to the
4296  *         first id of a group of cells. For example cells in contact with the *i*-th
4297  *         point are described by following range of indices:
4298  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4299  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4300  *         Number of cells in contact with the *i*-th point is
4301  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4302  *  \throw If the coordinates array is not set.
4303  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4304  *
4305  *  \if ENABLE_EXAMPLES
4306  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4307  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4308  *  \endif
4309  */
4310 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4311                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4312 {
4313   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4314   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4315 }
4316
4317 /*!
4318  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4319  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4320  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4321  * 
4322  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4323  */
4324 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4325 {
4326   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4327   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4328 }
4329
4330 /*!
4331  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4332  * least two its edges intersect each other anywhere except their extremities. An
4333  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4334  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4335  *         cleared before filling in.
4336  *  \param [in] eps - precision.
4337  *  \throw If \a this->getMeshDimension() != 2.
4338  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4339  */
4340 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4341 {
4342   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4343   if(getMeshDimension()!=2)
4344     throw INTERP_KERNEL::Exception(msg);
4345   int spaceDim=getSpaceDimension();
4346   if(spaceDim!=2 && spaceDim!=3)
4347     throw INTERP_KERNEL::Exception(msg);
4348   const mcIdType *conn=_nodal_connec->getConstPointer();
4349   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4350   mcIdType nbOfCells=getNumberOfCells();
4351   std::vector<double> cell2DinS2;
4352   for(mcIdType i=0;i<nbOfCells;i++)
4353     {
4354       mcIdType offset=connI[i];
4355       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4356       if(nbOfNodesForCell<=3)
4357         continue;
4358       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4359       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4360       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4361         cells.push_back(i);
4362       cell2DinS2.clear();
4363     }
4364 }
4365
4366 /*!
4367  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4368  *
4369  * 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.
4370  * 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.
4371  *
4372  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4373  * This convex envelop is computed using Jarvis march algorithm.
4374  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4375  * 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)
4376  * 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.
4377  *
4378  * \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.
4379  * \sa MEDCouplingUMesh::colinearize2D
4380  */
4381 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4382 {
4383   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4384     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4385   checkFullyDefined();
4386   const double *coords=getCoords()->getConstPointer();
4387   mcIdType nbOfCells=getNumberOfCells();
4388   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4389   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4390   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4391   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4392   *workIndexOut=0;
4393   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4394   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4395   std::set<INTERP_KERNEL::NormalizedCellType> types;
4396   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4397   isChanged->alloc(0,1);
4398   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4399     {
4400       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4401       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4402         isChanged->pushBackSilent(i);
4403       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4404       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4405     }
4406   if(isChanged->empty())
4407     return 0;
4408   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4409   _types=types;
4410   return isChanged.retn();
4411 }
4412
4413 /*!
4414  * This method is \b NOT const because it can modify \a this.
4415  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4416  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4417  * \param policy specifies the type of extrusion chosen:
4418  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4419  *   will be repeated to build each level
4420  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4421  *   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
4422  *   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
4423  *   arc.
4424  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4425  */
4426 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4427 {
4428   checkFullyDefined();
4429   mesh1D->checkFullyDefined();
4430   if(!mesh1D->isContiguous1D())
4431     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4432   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4433     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4434   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4435     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4436   if(mesh1D->getMeshDimension()!=1)
4437     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4438   bool isQuad=false;
4439   if(isPresenceOfQuadratic())
4440     {
4441       if(mesh1D->isFullyQuadratic())
4442         isQuad=true;
4443       else
4444         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4445     }
4446   mcIdType oldNbOfNodes(getNumberOfNodes());
4447   MCAuto<DataArrayDouble> newCoords;
4448   switch(policy)
4449   {
4450     case 0:
4451       {
4452         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4453         break;
4454       }
4455     case 1:
4456       {
4457         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4458         break;
4459       }
4460     default:
4461       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4462   }
4463   setCoords(newCoords);
4464   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4465   updateTime();
4466   return ret.retn();
4467 }
4468
4469
4470 /*!
4471  * Checks if \a this mesh is constituted by only quadratic cells.
4472  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4473  *  \throw If the coordinates array is not set.
4474  *  \throw If the nodal connectivity of cells is not defined.
4475  */
4476 bool MEDCouplingUMesh::isFullyQuadratic() const
4477 {
4478   checkFullyDefined();
4479   bool ret=true;
4480   mcIdType nbOfCells=getNumberOfCells();
4481   for(mcIdType i=0;i<nbOfCells && ret;i++)
4482     {
4483       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4484       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4485       ret=cm.isQuadratic();
4486     }
4487   return ret;
4488 }
4489
4490 /*!
4491  * Checks if \a this mesh includes any quadratic cell.
4492  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4493  *  \throw If the coordinates array is not set.
4494  *  \throw If the nodal connectivity of cells is not defined.
4495  */
4496 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4497 {
4498   checkFullyDefined();
4499   bool ret=false;
4500   mcIdType nbOfCells=getNumberOfCells();
4501   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4502     {
4503       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4504       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4505       ret=cm.isQuadratic();
4506     }
4507   return ret;
4508 }
4509
4510 /*!
4511  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4512  * this mesh, it remains unchanged.
4513  *  \throw If the coordinates array is not set.
4514  *  \throw If the nodal connectivity of cells is not defined.
4515  */
4516 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4517 {
4518   checkFullyDefined();
4519   mcIdType nbOfCells=getNumberOfCells();
4520   mcIdType delta=0;
4521   const mcIdType *iciptr=_nodal_connec_index->begin();
4522   for(mcIdType i=0;i<nbOfCells;i++)
4523     {
4524       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4525       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4526       if(cm.isQuadratic())
4527         {
4528           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4529           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4530           if(!cml.isDynamic())
4531             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4532           else
4533             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4534         }
4535     }
4536   if(delta==0)
4537     return ;
4538   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4539   const mcIdType *icptr(_nodal_connec->begin());
4540   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4541   newConnI->alloc(nbOfCells+1,1);
4542   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4543   *ociptr=0;
4544   _types.clear();
4545   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4546     {
4547       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4548       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4549       if(!cm.isQuadratic())
4550         {
4551           _types.insert(type);
4552           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4553           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4554         }
4555       else
4556         {
4557           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4558           _types.insert(typel);
4559           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4560           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4561           if(cml.isDynamic())
4562             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4563           *ocptr++=ToIdType(typel);
4564           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4565           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4566         }
4567     }
4568   setConnectivity(newConn,newConnI,false);
4569 }
4570
4571 /*!
4572  * This method converts all linear cell in \a this to quadratic one.
4573  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4574  * 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)
4575  * 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.
4576  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4577  * end of the existing coordinates.
4578  *
4579  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4580  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4581  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4582  *
4583  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4584  *
4585  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4586  */
4587 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4588 {
4589   DataArrayIdType *conn=0,*connI=0;
4590   DataArrayDouble *coords=0;
4591   std::set<INTERP_KERNEL::NormalizedCellType> types;
4592   checkFullyDefined();
4593   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4594   MCAuto<DataArrayDouble> coordsSafe;
4595   int meshDim=getMeshDimension();
4596   switch(conversionType)
4597   {
4598     case 0:
4599       switch(meshDim)
4600       {
4601         case 1:
4602           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4603           connSafe=conn; connISafe=connI; coordsSafe=coords;
4604           break;
4605         case 2:
4606           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4607           connSafe=conn; connISafe=connI; coordsSafe=coords;
4608           break;
4609         case 3:
4610           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4611           connSafe=conn; connISafe=connI; coordsSafe=coords;
4612           break;
4613         default:
4614           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4615       }
4616       break;
4617         case 1:
4618           {
4619             switch(meshDim)
4620             {
4621               case 1:
4622                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4623                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4624                 break;
4625               case 2:
4626                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4627                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4628                 break;
4629               case 3:
4630                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4631                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4632                 break;
4633               default:
4634                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4635             }
4636             break;
4637           }
4638         default:
4639           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4640   }
4641   setConnectivity(connSafe,connISafe,false);
4642   _types=types;
4643   setCoords(coordsSafe);
4644   return ret.retn();
4645 }
4646
4647 /*!
4648  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4649  * so that the number of cells remains the same. Quadratic faces are converted to
4650  * polygons. This method works only for 2D meshes in
4651  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4652  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4653  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4654  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4655  *         a polylinized edge constituting the input polygon.
4656  *  \throw If the coordinates array is not set.
4657  *  \throw If the nodal connectivity of cells is not defined.
4658  *  \throw If \a this->getMeshDimension() != 2.
4659  *  \throw If \a this->getSpaceDimension() != 2.
4660  */
4661 void MEDCouplingUMesh::tessellate2D(double eps)
4662 {
4663   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4664   if(spaceDim!=2)
4665     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4666   switch(meshDim)
4667     {
4668     case 1:
4669       return tessellate2DCurveInternal(eps);
4670     case 2:
4671       return tessellate2DInternal(eps);
4672     default:
4673       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4674     }
4675 }
4676
4677 #if 0
4678 /*!
4679  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4680  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4681  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4682  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4683  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4684  * This method can be seen as the opposite method of colinearize2D.
4685  * 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
4686  * to avoid to modify the numbering of existing nodes.
4687  *
4688  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4689  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4690  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4691  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4692  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4693  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4694  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4695  *
4696  * \sa buildDescendingConnectivity2
4697  */
4698 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4699                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4700 {
4701   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4702     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4703   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4704   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4705     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4706   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4707     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4708   //DataArrayIdType *out0(0),*outi0(0);
4709   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4710   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4711   //out0s=out0s->buildUnique(); out0s->sort(true);
4712 }
4713 #endif
4714
4715
4716 /*!
4717  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4718  * In addition, returns an array mapping new cells to old ones. <br>
4719  * This method typically increases the number of cells in \a this mesh
4720  * but the number of nodes remains \b unchanged.
4721  * That's why the 3D splitting policies
4722  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4723  *  \param [in] policy - specifies a pattern used for splitting.
4724  * The semantic of \a policy is:
4725  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4726  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4727  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4728  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4729  *
4730  *
4731  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4732  *          an id of old cell producing it. The caller is to delete this array using
4733  *         decrRef() as it is no more needed.
4734  *
4735  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4736  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4737  *          and \a this->getMeshDimension() != 3.
4738  *  \throw If \a policy is not one of the four discussed above.
4739  *  \throw If the nodal connectivity of cells is not defined.
4740  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4741  */
4742 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4743 {
4744   switch(policy)
4745   {
4746     case 0:
4747       return simplexizePol0();
4748     case 1:
4749       return simplexizePol1();
4750     case INTERP_KERNEL::PLANAR_FACE_5:
4751         return simplexizePlanarFace5();
4752     case INTERP_KERNEL::PLANAR_FACE_6:
4753         return simplexizePlanarFace6();
4754     default:
4755       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)");
4756   }
4757 }
4758
4759 /*!
4760  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4761  * - 1D: INTERP_KERNEL::NORM_SEG2
4762  * - 2D: INTERP_KERNEL::NORM_TRI3
4763  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4764  *
4765  * This method is useful for users that need to use P1 field services as
4766  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4767  * All these methods need mesh support containing only simplex cells.
4768  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4769  *  \throw If the coordinates array is not set.
4770  *  \throw If the nodal connectivity of cells is not defined.
4771  *  \throw If \a this->getMeshDimension() < 1.
4772  */
4773 bool MEDCouplingUMesh::areOnlySimplexCells() const
4774 {
4775   checkFullyDefined();
4776   int mdim=getMeshDimension();
4777   if(mdim<1 || mdim>3)
4778     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4779   mcIdType nbCells=getNumberOfCells();
4780   const mcIdType *conn=_nodal_connec->begin();
4781   const mcIdType *connI=_nodal_connec_index->begin();
4782   for(mcIdType i=0;i<nbCells;i++)
4783     {
4784       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4785       if(!cm.isSimplex())
4786         return false;
4787     }
4788   return true;
4789 }
4790
4791
4792
4793 /*!
4794  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4795  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4796  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4797  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4798  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4799  * so it can be useful to call mergeNodes() before calling this method.
4800  *  \throw If \a this->getMeshDimension() <= 1.
4801  *  \throw If the coordinates array is not set.
4802  *  \throw If the nodal connectivity of cells is not defined.
4803  */
4804 void MEDCouplingUMesh::convertDegeneratedCells()
4805 {
4806   checkFullyDefined();
4807   if(getMeshDimension()<=1)
4808     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4809   mcIdType nbOfCells=getNumberOfCells();
4810   if(nbOfCells<1)
4811     return ;
4812   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4813   mcIdType *conn=_nodal_connec->getPointer();
4814   mcIdType *index=_nodal_connec_index->getPointer();
4815   mcIdType posOfCurCell=0;
4816   mcIdType newPos=0;
4817   mcIdType lgthOfCurCell;
4818   for(mcIdType i=0;i<nbOfCells;i++)
4819     {
4820       lgthOfCurCell=index[i+1]-posOfCurCell;
4821       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4822       mcIdType newLgth;
4823       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4824                                                                                                      conn+newPos+1,newLgth);
4825       conn[newPos]=newType;
4826       newPos+=newLgth+1;
4827       posOfCurCell=index[i+1];
4828       index[i+1]=newPos;
4829     }
4830   if(newPos!=initMeshLgth)
4831     _nodal_connec->reAlloc(newPos);
4832   computeTypes();
4833 }
4834
4835 /*!
4836  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4837  * A cell is flat in the following cases:
4838  *   - for a linear cell, all points in the connectivity are equal
4839  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4840  *   identical quadratic points
4841  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4842  *      this array using decrRef() as it is no more needed.
4843  */
4844 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4845 {
4846   checkFullyDefined();
4847   if(getMeshDimension()<=1)
4848     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4849   mcIdType nbOfCells=getNumberOfCells();
4850   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4851   if(nbOfCells<1)
4852     return ret.retn();
4853   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4854   mcIdType *conn=_nodal_connec->getPointer();
4855   mcIdType *index=_nodal_connec_index->getPointer();
4856   mcIdType posOfCurCell=0;
4857   mcIdType newPos=0;
4858   mcIdType lgthOfCurCell, nbDelCells(0);
4859   for(mcIdType i=0;i<nbOfCells;i++)
4860     {
4861       lgthOfCurCell=index[i+1]-posOfCurCell;
4862       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4863       mcIdType newLgth;
4864       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4865                                                                                                      conn+newPos+1,newLgth);
4866       // Shall we delete the cell if it is completely degenerated:
4867       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4868       if (delCell)
4869         {
4870           nbDelCells++;
4871           ret->pushBackSilent(i);
4872         }
4873       else   //if the cell is to be deleted, simply stay at the same place
4874         {
4875           conn[newPos]=newType;
4876           newPos+=newLgth+1;
4877         }
4878       posOfCurCell=index[i+1];
4879       index[i+1-nbDelCells]=newPos;
4880     }
4881   if(newPos!=initMeshLgth)
4882     _nodal_connec->reAlloc(newPos);
4883   const mcIdType nCellDel=ret->getNumberOfTuples();
4884   if (nCellDel)
4885     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4886   computeTypes();
4887   return ret.retn();
4888 }
4889
4890 /*!
4891  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4892  * Only connectivity is considered here.
4893  */
4894 bool MEDCouplingUMesh::removeDegenerated1DCells()
4895 {
4896   checkConnectivityFullyDefined();
4897   if(getMeshDimension()!=1)
4898     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4899   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4900   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4901   {
4902     for(std::size_t i=0;i<nbCells;i++)
4903       {
4904         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4905         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4906           {
4907             if(conn[conni[i]+1]!=conn[conni[i]+2])
4908               {
4909                 newSize++;
4910                 newSize2+=conni[i+1]-conni[i];
4911               }
4912           }
4913         else
4914           {
4915             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4916             throw INTERP_KERNEL::Exception(oss.str());
4917           }
4918       }
4919   }
4920   if(newSize==nbCells)//no cells has been removed -> do nothing
4921     return false;
4922   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4923   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4924   for(std::size_t i=0;i<nbCells;i++)
4925     {
4926       if(conn[conni[i]+1]!=conn[conni[i]+2])
4927         {
4928           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4929           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4930           newConnIPtr++;
4931         }
4932     }
4933   setConnectivity(newConn,newConnI,true);
4934   return true;
4935 }
4936
4937 /*!
4938  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4939  * A cell is considered to be oriented correctly if an angle between its
4940  * normal vector and a given vector is less than \c PI / \c 2.
4941  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4942  *         cells.
4943  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4944  *         checked.
4945  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4946  *         is not cleared before filling in.
4947  *  \throw If \a this->getMeshDimension() != 2.
4948  *  \throw If \a this->getSpaceDimension() != 3.
4949  *
4950  *  \if ENABLE_EXAMPLES
4951  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4952  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4953  *  \endif
4954  */
4955 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4956 {
4957   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4958     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4959   mcIdType nbOfCells=getNumberOfCells();
4960   const mcIdType *conn=_nodal_connec->begin();
4961   const mcIdType *connI=_nodal_connec_index->begin();
4962   const double *coordsPtr=_coords->begin();
4963   for(mcIdType i=0;i<nbOfCells;i++)
4964     {
4965       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4966       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4967         {
4968           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4969           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4970             cells.push_back(i);
4971         }
4972     }
4973 }
4974
4975 /*!
4976  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4977  * considered to be oriented correctly if an angle between its normal vector and a
4978  * given vector is less than \c PI / \c 2.
4979  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4980  *         cells.
4981  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4982  *         checked.
4983  *  \throw If \a this->getMeshDimension() != 2.
4984  *  \throw If \a this->getSpaceDimension() != 3.
4985  *
4986  *  \if ENABLE_EXAMPLES
4987  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4988  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4989  *  \endif
4990  *
4991  *  \sa changeOrientationOfCells
4992  */
4993 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4994 {
4995   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4996     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4997   mcIdType nbOfCells=getNumberOfCells();
4998   mcIdType *conn(_nodal_connec->getPointer());
4999   const mcIdType *connI(_nodal_connec_index->begin());
5000   const double *coordsPtr(_coords->begin());
5001   bool isModified(false);
5002   for(mcIdType i=0;i<nbOfCells;i++)
5003     {
5004       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5005       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5006         {
5007           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5008           bool isQuadratic(cm.isQuadratic());
5009           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5010             {
5011               isModified=true;
5012               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5013             }
5014         }
5015     }
5016   if(isModified)
5017     _nodal_connec->declareAsNew();
5018   updateTime();
5019 }
5020
5021 /*!
5022  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5023  *
5024  * \sa orientCorrectly2DCells
5025  */
5026 void MEDCouplingUMesh::changeOrientationOfCells()
5027 {
5028   int mdim(getMeshDimension());
5029   if(mdim!=2 && mdim!=1)
5030     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5031   mcIdType nbOfCells=getNumberOfCells();
5032   mcIdType *conn(_nodal_connec->getPointer());
5033   const mcIdType *connI(_nodal_connec_index->begin());
5034   if(mdim==2)
5035     {//2D
5036       for(mcIdType i=0;i<nbOfCells;i++)
5037         {
5038           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5039           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5040           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5041         }
5042     }
5043   else
5044     {//1D
5045       for(mcIdType i=0;i<nbOfCells;i++)
5046         {
5047           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5048           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5049           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5050         }
5051     }
5052 }
5053
5054 /*!
5055  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5056  * oriented facets. The normal vector of the facet should point out of the cell.
5057  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5058  *         is not cleared before filling in.
5059  *  \throw If \a this->getMeshDimension() != 3.
5060  *  \throw If \a this->getSpaceDimension() != 3.
5061  *  \throw If the coordinates array is not set.
5062  *  \throw If the nodal connectivity of cells is not defined.
5063  *
5064  *  \if ENABLE_EXAMPLES
5065  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5066  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5067  *  \endif
5068  */
5069 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5070 {
5071   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5072     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5073   mcIdType nbOfCells=getNumberOfCells();
5074   const mcIdType *conn=_nodal_connec->begin();
5075   const mcIdType *connI=_nodal_connec_index->begin();
5076   const double *coordsPtr=_coords->begin();
5077   for(mcIdType i=0;i<nbOfCells;i++)
5078     {
5079       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5080       if(type==INTERP_KERNEL::NORM_POLYHED)
5081         {
5082           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5083             cells.push_back(i);
5084         }
5085     }
5086 }
5087
5088 /*!
5089  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5090  * out of the cell.
5091  *  \throw If \a this->getMeshDimension() != 3.
5092  *  \throw If \a this->getSpaceDimension() != 3.
5093  *  \throw If the coordinates array is not set.
5094  *  \throw If the nodal connectivity of cells is not defined.
5095  *  \throw If the reparation fails.
5096  *
5097  *  \if ENABLE_EXAMPLES
5098  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5099  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5100  *  \endif
5101  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5102  */
5103 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5104 {
5105   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5106     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5107   mcIdType nbOfCells=getNumberOfCells();
5108   mcIdType *conn=_nodal_connec->getPointer();
5109   const mcIdType *connI=_nodal_connec_index->begin();
5110   const double *coordsPtr=_coords->begin();
5111   for(mcIdType i=0;i<nbOfCells;i++)
5112     {
5113       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5114       if(type==INTERP_KERNEL::NORM_POLYHED)
5115         {
5116           try
5117           {
5118               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5119                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5120           }
5121           catch(INTERP_KERNEL::Exception& e)
5122           {
5123               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5124               throw INTERP_KERNEL::Exception(oss.str());
5125           }
5126         }
5127     }
5128   updateTime();
5129 }
5130
5131 /*!
5132  * This method invert orientation of all cells in \a this.
5133  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5134  * This method only operates on the connectivity so coordinates are not touched at all.
5135  */
5136 void MEDCouplingUMesh::invertOrientationOfAllCells()
5137 {
5138   checkConnectivityFullyDefined();
5139   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5140   mcIdType *conn(_nodal_connec->getPointer());
5141   const mcIdType *conni(_nodal_connec_index->begin());
5142   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5143     {
5144       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5145       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5146       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5147         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5148     }
5149   updateTime();
5150 }
5151
5152 /*!
5153  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5154  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5155  * according to which the first facet of the cell should be oriented to have the normal vector
5156  * pointing out of cell.
5157  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5158  *         cells. The caller is to delete this array using decrRef() as it is no more
5159  *         needed.
5160  *  \throw If \a this->getMeshDimension() != 3.
5161  *  \throw If \a this->getSpaceDimension() != 3.
5162  *  \throw If the coordinates array is not set.
5163  *  \throw If the nodal connectivity of cells is not defined.
5164  *
5165  *  \if ENABLE_EXAMPLES
5166  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5167  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5168  *  \endif
5169  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5170  */
5171 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5172 {
5173   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5174   if(getMeshDimension()!=3)
5175     throw INTERP_KERNEL::Exception(msg);
5176   int spaceDim=getSpaceDimension();
5177   if(spaceDim!=3)
5178     throw INTERP_KERNEL::Exception(msg);
5179   //
5180   mcIdType nbOfCells=getNumberOfCells();
5181   mcIdType *conn=_nodal_connec->getPointer();
5182   const mcIdType *connI=_nodal_connec_index->begin();
5183   const double *coo=getCoords()->begin();
5184   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5185   for(mcIdType i=0;i<nbOfCells;i++)
5186     {
5187       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5188       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5189         {
5190           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5191             {
5192               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5193               cells->pushBackSilent(i);
5194             }
5195         }
5196     }
5197   return cells.retn();
5198 }
5199
5200 /*!
5201  * This method is a faster method to correct orientation of all 3D cells in \a this.
5202  * 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.
5203  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5204  *
5205  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5206  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5207  */
5208 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5209 {
5210   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5211     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5212   mcIdType nbOfCells=getNumberOfCells();
5213   mcIdType *conn=_nodal_connec->getPointer();
5214   const mcIdType *connI=_nodal_connec_index->begin();
5215   const double *coordsPtr=_coords->begin();
5216   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5217   for(mcIdType i=0;i<nbOfCells;i++)
5218     {
5219       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5220       switch(type)
5221       {
5222         case INTERP_KERNEL::NORM_TETRA4:
5223           {
5224             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5225               {
5226                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5227                 ret->pushBackSilent(i);
5228               }
5229             break;
5230           }
5231         case INTERP_KERNEL::NORM_PYRA5:
5232           {
5233             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5234               {
5235                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5236                 ret->pushBackSilent(i);
5237               }
5238             break;
5239           }
5240         case INTERP_KERNEL::NORM_PENTA6:
5241         case INTERP_KERNEL::NORM_HEXA8:
5242         case INTERP_KERNEL::NORM_HEXGP12:
5243           {
5244             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5245               {
5246                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5247                 ret->pushBackSilent(i);
5248               }
5249             break;
5250           }
5251         case INTERP_KERNEL::NORM_POLYHED:
5252           {
5253             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5254               {
5255                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5256                 ret->pushBackSilent(i);
5257               }
5258             break;
5259           }
5260         default:
5261           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 !");
5262       }
5263     }
5264   updateTime();
5265   return ret.retn();
5266 }
5267
5268 /*!
5269  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5270  * If it is not the case an exception will be thrown.
5271  * This method is fast because the first cell of \a this is used to compute the plane.
5272  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5273  * \param pos output of size at least 3 used to store a point owned of searched plane.
5274  */
5275 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5276 {
5277   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5278     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5279   const mcIdType *conn=_nodal_connec->begin();
5280   const mcIdType *connI=_nodal_connec_index->begin();
5281   const double *coordsPtr=_coords->begin();
5282   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5283   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5284 }
5285
5286 /*!
5287  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5288  * cells. Currently cells of the following types are treated:
5289  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5290  * For a cell of other type an exception is thrown.
5291  * Space dimension of a 2D mesh can be either 2 or 3.
5292  * The Edge Ratio of a cell \f$t\f$ is:
5293  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5294  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5295  *  the smallest edge lengths of \f$t\f$.
5296  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5297  *          cells and one time, lying on \a this mesh. The caller is to delete this
5298  *          field using decrRef() as it is no more needed.
5299  *  \throw If the coordinates array is not set.
5300  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5301  *  \throw If the connectivity data array has more than one component.
5302  *  \throw If the connectivity data array has a named component.
5303  *  \throw If the connectivity index data array has more than one component.
5304  *  \throw If the connectivity index data array has a named component.
5305  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5306  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5307  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5308  */
5309 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5310 {
5311   checkConsistencyLight();
5312   int spaceDim=getSpaceDimension();
5313   int meshDim=getMeshDimension();
5314   if(spaceDim!=2 && spaceDim!=3)
5315     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5316   if(meshDim!=2 && meshDim!=3)
5317     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5318   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5319   ret->setMesh(this);
5320   mcIdType nbOfCells=getNumberOfCells();
5321   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5322   arr->alloc(nbOfCells,1);
5323   double *pt=arr->getPointer();
5324   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5325   const mcIdType *conn=_nodal_connec->begin();
5326   const mcIdType *connI=_nodal_connec_index->begin();
5327   const double *coo=_coords->begin();
5328   double tmp[12];
5329   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5330     {
5331       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5332       switch(t)
5333       {
5334         case INTERP_KERNEL::NORM_TRI3:
5335           {
5336             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5337             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5338             break;
5339           }
5340         case INTERP_KERNEL::NORM_QUAD4:
5341           {
5342             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5343             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5344             break;
5345           }
5346         case INTERP_KERNEL::NORM_TETRA4:
5347           {
5348             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5349             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5350             break;
5351           }
5352         default:
5353           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5354       }
5355       conn+=connI[i+1]-connI[i];
5356     }
5357   ret->setName("EdgeRatio");
5358   ret->synchronizeTimeWithSupport();
5359   return ret.retn();
5360 }
5361
5362 /*!
5363  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5364  * cells. Currently cells of the following types are treated:
5365  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5366  * For a cell of other type an exception is thrown.
5367  * Space dimension of a 2D mesh can be either 2 or 3.
5368  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5369  *          cells and one time, lying on \a this mesh. The caller is to delete this
5370  *          field using decrRef() as it is no more needed.
5371  *  \throw If the coordinates array is not set.
5372  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5373  *  \throw If the connectivity data array has more than one component.
5374  *  \throw If the connectivity data array has a named component.
5375  *  \throw If the connectivity index data array has more than one component.
5376  *  \throw If the connectivity index data array has a named component.
5377  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5378  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5379  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5380  */
5381 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5382 {
5383   checkConsistencyLight();
5384   int spaceDim=getSpaceDimension();
5385   int meshDim=getMeshDimension();
5386   if(spaceDim!=2 && spaceDim!=3)
5387     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5388   if(meshDim!=2 && meshDim!=3)
5389     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5390   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5391   ret->setMesh(this);
5392   mcIdType nbOfCells=getNumberOfCells();
5393   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5394   arr->alloc(nbOfCells,1);
5395   double *pt=arr->getPointer();
5396   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5397   const mcIdType *conn=_nodal_connec->begin();
5398   const mcIdType *connI=_nodal_connec_index->begin();
5399   const double *coo=_coords->begin();
5400   double tmp[12];
5401   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5402     {
5403       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5404       switch(t)
5405       {
5406         case INTERP_KERNEL::NORM_TRI3:
5407           {
5408             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5409             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5410             break;
5411           }
5412         case INTERP_KERNEL::NORM_QUAD4:
5413           {
5414             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5415             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5416             break;
5417           }
5418         case INTERP_KERNEL::NORM_TETRA4:
5419           {
5420             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5421             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5422             break;
5423           }
5424         default:
5425           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5426       }
5427       conn+=connI[i+1]-connI[i];
5428     }
5429   ret->setName("AspectRatio");
5430   ret->synchronizeTimeWithSupport();
5431   return ret.retn();
5432 }
5433
5434 /*!
5435  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5436  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5437  * in 3D space. Currently only cells of the following types are
5438  * treated: INTERP_KERNEL::NORM_QUAD4.
5439  * For a cell of other type an exception is thrown.
5440  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5441  * Defining
5442  * \f$t=\vec{da}\times\vec{ab}\f$,
5443  * \f$u=\vec{ab}\times\vec{bc}\f$
5444  * \f$v=\vec{bc}\times\vec{cd}\f$
5445  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5446  *  \f[
5447  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5448  *  \f]
5449  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5450  *          cells and one time, lying on \a this mesh. The caller is to delete this
5451  *          field using decrRef() as it is no more needed.
5452  *  \throw If the coordinates array is not set.
5453  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5454  *  \throw If the connectivity data array has more than one component.
5455  *  \throw If the connectivity data array has a named component.
5456  *  \throw If the connectivity index data array has more than one component.
5457  *  \throw If the connectivity index data array has a named component.
5458  *  \throw If \a this->getMeshDimension() != 2.
5459  *  \throw If \a this->getSpaceDimension() != 3.
5460  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5461  */
5462 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5463 {
5464   checkConsistencyLight();
5465   int spaceDim=getSpaceDimension();
5466   int meshDim=getMeshDimension();
5467   if(spaceDim!=3)
5468     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5469   if(meshDim!=2)
5470     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5471   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5472   ret->setMesh(this);
5473   mcIdType nbOfCells=getNumberOfCells();
5474   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5475   arr->alloc(nbOfCells,1);
5476   double *pt=arr->getPointer();
5477   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5478   const mcIdType *conn=_nodal_connec->begin();
5479   const mcIdType *connI=_nodal_connec_index->begin();
5480   const double *coo=_coords->begin();
5481   double tmp[12];
5482   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5483     {
5484       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5485       switch(t)
5486       {
5487         case INTERP_KERNEL::NORM_QUAD4:
5488           {
5489             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5490             *pt=INTERP_KERNEL::quadWarp(tmp);
5491             break;
5492           }
5493         default:
5494           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5495       }
5496       conn+=connI[i+1]-connI[i];
5497     }
5498   ret->setName("Warp");
5499   ret->synchronizeTimeWithSupport();
5500   return ret.retn();
5501 }
5502
5503
5504 /*!
5505  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5506  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5507  * treated: INTERP_KERNEL::NORM_QUAD4.
5508  * The skew is computed as follow for a quad with points (a,b,c,d): let
5509  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5510  * then the skew is computed as:
5511  *  \f[
5512  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5513  *  \f]
5514  *
5515  * For a cell of other type an exception is thrown.
5516  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5517  *          cells and one time, lying on \a this mesh. The caller is to delete this
5518  *          field using decrRef() as it is no more needed.
5519  *  \throw If the coordinates array is not set.
5520  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5521  *  \throw If the connectivity data array has more than one component.
5522  *  \throw If the connectivity data array has a named component.
5523  *  \throw If the connectivity index data array has more than one component.
5524  *  \throw If the connectivity index data array has a named component.
5525  *  \throw If \a this->getMeshDimension() != 2.
5526  *  \throw If \a this->getSpaceDimension() != 3.
5527  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5528  */
5529 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5530 {
5531   checkConsistencyLight();
5532   int spaceDim=getSpaceDimension();
5533   int meshDim=getMeshDimension();
5534   if(spaceDim!=3)
5535     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5536   if(meshDim!=2)
5537     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5538   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5539   ret->setMesh(this);
5540   mcIdType nbOfCells=getNumberOfCells();
5541   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5542   arr->alloc(nbOfCells,1);
5543   double *pt=arr->getPointer();
5544   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5545   const mcIdType *conn=_nodal_connec->begin();
5546   const mcIdType *connI=_nodal_connec_index->begin();
5547   const double *coo=_coords->begin();
5548   double tmp[12];
5549   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5550     {
5551       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5552       switch(t)
5553       {
5554         case INTERP_KERNEL::NORM_QUAD4:
5555           {
5556             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5557             *pt=INTERP_KERNEL::quadSkew(tmp);
5558             break;
5559           }
5560         default:
5561           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5562       }
5563       conn+=connI[i+1]-connI[i];
5564     }
5565   ret->setName("Skew");
5566   ret->synchronizeTimeWithSupport();
5567   return ret.retn();
5568 }
5569
5570 /*!
5571  * 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.
5572  *
5573  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5574  *
5575  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5576  */
5577 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5578 {
5579   checkConsistencyLight();
5580   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5581   ret->setMesh(this);
5582   std::set<INTERP_KERNEL::NormalizedCellType> types;
5583   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5584   int spaceDim(getSpaceDimension());
5585   mcIdType nbCells(getNumberOfCells());
5586   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5587   arr->alloc(nbCells,1);
5588   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5589     {
5590       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5591       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5592       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5593     }
5594   ret->setArray(arr);
5595   ret->setName("Diameter");
5596   return ret.retn();
5597 }
5598
5599 /*!
5600  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5601  *
5602  * \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)
5603  *                         For all other cases this input parameter is ignored.
5604  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5605  *
5606  * \throw If \a this is not fully set (coordinates and connectivity).
5607  * \throw If a cell in \a this has no valid nodeId.
5608  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5609  */
5610 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5611 {
5612   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5613   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.
5614     return getBoundingBoxForBBTreeFast();
5615   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5616     {
5617       bool presenceOfQuadratic(false);
5618       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5619         {
5620           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5621           if(cm.isQuadratic())
5622             presenceOfQuadratic=true;
5623         }
5624       if(!presenceOfQuadratic)
5625         return getBoundingBoxForBBTreeFast();
5626       if(mDim==2 && sDim==2)
5627         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5628       else
5629         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5630     }
5631   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) !");
5632 }
5633
5634 /*!
5635  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5636  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5637  *
5638  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5639  *
5640  * \throw If \a this is not fully set (coordinates and connectivity).
5641  * \throw If a cell in \a this has no valid nodeId.
5642  */
5643 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5644 {
5645   checkFullyDefined();
5646   int spaceDim(getSpaceDimension());
5647   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5648   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5649   double *bbox(ret->getPointer());
5650   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5651     {
5652       bbox[2*i]=std::numeric_limits<double>::max();
5653       bbox[2*i+1]=-std::numeric_limits<double>::max();
5654     }
5655   const double *coordsPtr(_coords->begin());
5656   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5657   for(mcIdType i=0;i<nbOfCells;i++)
5658     {
5659       mcIdType offset=connI[i]+1;
5660       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5661       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5662         {
5663           mcIdType nodeId=conn[offset+j];
5664           if(nodeId>=0 && nodeId<nbOfNodes)
5665             {
5666               for(int k=0;k<spaceDim;k++)
5667                 {
5668                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5669                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5670                 }
5671               kk++;
5672             }
5673         }
5674       if(kk==0)
5675         {
5676           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5677           throw INTERP_KERNEL::Exception(oss.str());
5678         }
5679     }
5680   return ret.retn();
5681 }
5682
5683 /*!
5684  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5685  * useful for 2D meshes having quadratic cells
5686  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5687  * the two extremities of the arc of circle).
5688  *
5689  * \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)
5690  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5691  * \throw If \a this is not fully defined.
5692  * \throw If \a this is not a mesh with meshDimension equal to 2.
5693  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5694  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5695  */
5696 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5697 {
5698   checkFullyDefined();
5699   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5700
5701   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5702   mcIdType nbOfCells=getNumberOfCells();
5703   if(spaceDim!=2 || mDim!=2)
5704     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!");
5705   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5706   double *bbox(ret->getPointer());
5707   const double *coords(_coords->begin());
5708   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5709   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5710     {
5711       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5712       mcIdType sz(connI[1]-connI[0]-1);
5713       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5714       INTERP_KERNEL::QuadraticPolygon *pol(0);
5715       for(mcIdType j=0;j<sz;j++)
5716         {
5717           mcIdType nodeId(conn[*connI+1+j]);
5718           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5719         }
5720       if(!cm.isQuadratic())
5721         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5722       else
5723         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5724       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5725       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5726     }
5727   return ret.retn();
5728 }
5729
5730 /*!
5731  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5732  * useful for 2D meshes having quadratic cells
5733  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5734  * the two extremities of the arc of circle).
5735  *
5736  * \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)
5737  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5738  * \throw If \a this is not fully defined.
5739  * \throw If \a this is not a mesh with meshDimension equal to 1.
5740  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5741  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5742  */
5743 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5744 {
5745   checkFullyDefined();
5746   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5747   mcIdType nbOfCells=getNumberOfCells();
5748   if(spaceDim!=2 || mDim!=1)
5749     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!");
5750   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5751   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5752   double *bbox(ret->getPointer());
5753   const double *coords(_coords->begin());
5754   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5755   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5756     {
5757       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5758       mcIdType sz(connI[1]-connI[0]-1);
5759       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5760       INTERP_KERNEL::Edge *edge(0);
5761       for(mcIdType j=0;j<sz;j++)
5762         {
5763           mcIdType nodeId(conn[*connI+1+j]);
5764           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5765         }
5766       if(!cm.isQuadratic())
5767         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5768       else
5769         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5770       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5771       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5772     }
5773   return ret.retn();
5774 }
5775
5776 /// @cond INTERNAL
5777
5778 namespace MEDCouplingImpl
5779 {
5780   class ConnReader
5781   {
5782   public:
5783     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5784     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5785   private:
5786     const mcIdType *_conn;
5787     mcIdType _val;
5788   };
5789
5790   class ConnReader2
5791   {
5792   public:
5793     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5794     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5795   private:
5796     const mcIdType *_conn;
5797     mcIdType _val;
5798   };
5799 }
5800
5801 /// @endcond
5802
5803 /*!
5804  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5805  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5806  * \a this is composed in cell types.
5807  * The returned array is of size 3*n where n is the number of different types present in \a this.
5808  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5809  * This parameter is kept only for compatibility with other method listed above.
5810  */
5811 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5812 {
5813   checkConnectivityFullyDefined();
5814   const mcIdType *conn=_nodal_connec->begin();
5815   const mcIdType *connI=_nodal_connec_index->begin();
5816   const mcIdType *work=connI;
5817   mcIdType nbOfCells=getNumberOfCells();
5818   std::size_t n=getAllGeoTypes().size();
5819   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5820   std::set<INTERP_KERNEL::NormalizedCellType> types;
5821   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5822     {
5823       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5824       if(types.find(typ)!=types.end())
5825         {
5826           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5827           oss << " is not contiguous !";
5828           throw INTERP_KERNEL::Exception(oss.str());
5829         }
5830       types.insert(typ);
5831       ret[3*i]=typ;
5832       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5833       ret[3*i+1]=ToIdType(std::distance(work,work2));
5834       work=work2;
5835     }
5836   return ret;
5837 }
5838
5839 /*!
5840  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5841  * only for types cell, type node is not managed.
5842  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5843  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5844  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5845  * If 2 or more same geometric type is in \a code and exception is thrown too.
5846  *
5847  * This method firstly checks
5848  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5849  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5850  * an exception is thrown too.
5851  *
5852  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5853  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5854  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5855  */
5856 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5857 {
5858   if(code.empty())
5859     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5860   std::size_t sz=code.size();
5861   std::size_t n=sz/3;
5862   if(sz%3!=0)
5863     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5864   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5865   mcIdType nb=0;
5866   bool isNoPflUsed=true;
5867   for(std::size_t i=0;i<n;i++)
5868     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5869       {
5870         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5871         nb+=code[3*i+1];
5872         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5873           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5874         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5875       }
5876   if(types.size()!=n)
5877     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5878   if(isNoPflUsed)
5879     {
5880       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5881         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5882       if(types.size()==_types.size())
5883         return 0;
5884     }
5885   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5886   ret->alloc(nb,1);
5887   mcIdType *retPtr=ret->getPointer();
5888   const mcIdType *connI=_nodal_connec_index->begin();
5889   const mcIdType *conn=_nodal_connec->begin();
5890   mcIdType nbOfCells=getNumberOfCells();
5891   const mcIdType *i=connI;
5892   int kk=0;
5893   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5894     {
5895       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5896       mcIdType offset=ToIdType(std::distance(connI,i));
5897       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5898       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5899       if(code[3*kk+2]==-1)
5900         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5901           *retPtr++=k+offset;
5902       else
5903         {
5904           mcIdType idInIdsPerType=code[3*kk+2];
5905           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5906             {
5907               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5908               if(zePfl)
5909                 {
5910                   zePfl->checkAllocated();
5911                   if(zePfl->getNumberOfComponents()==1)
5912                     {
5913                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5914                         {
5915                           if(*k>=0 && *k<nbOfCellsOfCurType)
5916                             *retPtr=(*k)+offset;
5917                           else
5918                             {
5919                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5920                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5921                               throw INTERP_KERNEL::Exception(oss.str());
5922                             }
5923                         }
5924                     }
5925                   else
5926                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5927                 }
5928               else
5929                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5930             }
5931           else
5932             {
5933               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5934               oss << " should be in [0," << idsPerType.size() << ") !";
5935               throw INTERP_KERNEL::Exception(oss.str());
5936             }
5937         }
5938       i=j;
5939     }
5940   return ret.retn();
5941 }
5942
5943 /*!
5944  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5945  * 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.
5946  * 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.
5947  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5948  *
5949  * \param [in] profile list of IDs constituing the profile
5950  * \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.
5951  * \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,
5952  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5953  * \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.
5954  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5955  * \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
5956  */
5957 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5958 {
5959   if(!profile)
5960     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5961   if(profile->getNumberOfComponents()!=1)
5962     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5963   checkConnectivityFullyDefined();
5964   const mcIdType *conn=_nodal_connec->begin();
5965   const mcIdType *connI=_nodal_connec_index->begin();
5966   mcIdType nbOfCells=getNumberOfCells();
5967   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5968   std::vector<mcIdType> typeRangeVals(1);
5969   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5970     {
5971       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5972       if(std::find(types.begin(),types.end(),curType)!=types.end())
5973         {
5974           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5975         }
5976       types.push_back(curType);
5977       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5978       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5979     }
5980   //
5981   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5982   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5983   MCAuto<DataArrayIdType> tmp0=castArr;
5984   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5985   MCAuto<DataArrayIdType> tmp2=castsPresent;
5986   //
5987   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5988   code.resize(3*nbOfCastsFinal);
5989   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5990   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5991   for(mcIdType i=0;i<nbOfCastsFinal;i++)
5992     {
5993       mcIdType castId=castsPresent->getIJ(i,0);
5994       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5995       idsInPflPerType2.push_back(tmp3);
5996       code[3*i]=ToIdType(types[castId]);
5997       code[3*i+1]=tmp3->getNumberOfTuples();
5998       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5999       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6000         {
6001           tmp4->copyStringInfoFrom(*profile);
6002           idsPerType2.push_back(tmp4);
6003           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6004         }
6005       else
6006         {
6007           code[3*i+2]=-1;
6008         }
6009     }
6010   std::size_t sz2=idsInPflPerType2.size();
6011   idsInPflPerType.resize(sz2);
6012   for(std::size_t i=0;i<sz2;i++)
6013     {
6014       DataArrayIdType *locDa=idsInPflPerType2[i];
6015       locDa->incrRef();
6016       idsInPflPerType[i]=locDa;
6017     }
6018   std::size_t sz=idsPerType2.size();
6019   idsPerType.resize(sz);
6020   for(std::size_t i=0;i<sz;i++)
6021     {
6022       DataArrayIdType *locDa=idsPerType2[i];
6023       locDa->incrRef();
6024       idsPerType[i]=locDa;
6025     }
6026 }
6027
6028 /*!
6029  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6030  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6031  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6032  * 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.
6033  */
6034 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6035 {
6036   checkFullyDefined();
6037   nM1LevMesh->checkFullyDefined();
6038   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6039     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6040   if(_coords!=nM1LevMesh->getCoords())
6041     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6042   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6043   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6044   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6045   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6046   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6047   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6048   tmp->setConnectivity(tmp0,tmp1);
6049   tmp->renumberCells(ret0->begin(),false);
6050   revDesc=tmp->getNodalConnectivity();
6051   revDescIndx=tmp->getNodalConnectivityIndex();
6052   DataArrayIdType *ret=0;
6053   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6054     {
6055       mcIdType tmp2;
6056       ret->getMaxValue(tmp2);
6057       ret->decrRef();
6058       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6059       throw INTERP_KERNEL::Exception(oss.str());
6060     }
6061   nM1LevMeshIds=ret;
6062   //
6063   revDesc->incrRef();
6064   revDescIndx->incrRef();
6065   ret1->incrRef();
6066   ret0->incrRef();
6067   meshnM1Old2New=ret0;
6068   return ret1;
6069 }
6070
6071 /*!
6072  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6073  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6074  * in "Old to New" mode.
6075  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6076  *          this array using decrRef() as it is no more needed.
6077  *  \throw If the nodal connectivity of cells is not defined.
6078  */
6079 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6080 {
6081   checkConnectivityFullyDefined();
6082   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6083   renumberCells(ret->begin(),false);
6084   return ret.retn();
6085 }
6086
6087 /*!
6088  * This methods checks that cells are sorted by their types.
6089  * This method makes asumption (no check) that connectivity is correctly set before calling.
6090  */
6091 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6092 {
6093   checkFullyDefined();
6094   const mcIdType *conn=_nodal_connec->begin();
6095   const mcIdType *connI=_nodal_connec_index->begin();
6096   mcIdType nbOfCells=getNumberOfCells();
6097   std::set<INTERP_KERNEL::NormalizedCellType> types;
6098   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6099     {
6100       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6101       if(types.find(curType)!=types.end())
6102         return false;
6103       types.insert(curType);
6104       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6105     }
6106   return true;
6107 }
6108
6109 /*!
6110  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6111  * The geometric type order is specified by MED file.
6112  *
6113  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6114  */
6115 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6116 {
6117   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6118 }
6119
6120 /*!
6121  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6122  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6123  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6124  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6125  */
6126 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6127 {
6128   checkFullyDefined();
6129   const mcIdType *conn=_nodal_connec->begin();
6130   const mcIdType *connI=_nodal_connec_index->begin();
6131   mcIdType nbOfCells=getNumberOfCells();
6132   if(nbOfCells==0)
6133     return true;
6134   mcIdType lastPos=-1;
6135   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6136   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6137     {
6138       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6139       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6140       if(isTypeExists!=orderEnd)
6141         {
6142           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6143           if(pos<=lastPos)
6144             return false;
6145           lastPos=pos;
6146           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6147         }
6148       else
6149         {
6150           if(sg.find(curType)==sg.end())
6151             {
6152               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6153               sg.insert(curType);
6154             }
6155           else
6156             return false;
6157         }
6158     }
6159   return true;
6160 }
6161
6162 /*!
6163  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6164  * 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
6165  * 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'.
6166  */
6167 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6168 {
6169   checkConnectivityFullyDefined();
6170   mcIdType nbOfCells=getNumberOfCells();
6171   const mcIdType *conn=_nodal_connec->begin();
6172   const mcIdType *connI=_nodal_connec_index->begin();
6173   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6174   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6175   tmpa->alloc(nbOfCells,1);
6176   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6177   tmpb->fillWithZero();
6178   mcIdType *tmp=tmpa->getPointer();
6179   mcIdType *tmp2=tmpb->getPointer();
6180   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6181     {
6182       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6183       if(where!=orderEnd)
6184         {
6185           mcIdType pos=ToIdType(std::distance(orderBg,where));
6186           tmp2[pos]++;
6187           tmp[std::distance(connI,i)]=pos;
6188         }
6189       else
6190         {
6191           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6192           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6193           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6194           throw INTERP_KERNEL::Exception(oss.str());
6195         }
6196     }
6197   nbPerType=tmpb.retn();
6198   return tmpa.retn();
6199 }
6200
6201 /*!
6202  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6203  *
6204  * \return a new object containing the old to new correspondence.
6205  *
6206  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6207  */
6208 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6209 {
6210   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6211 }
6212
6213 /*!
6214  * 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.
6215  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6216  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6217  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6218  */
6219 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6220 {
6221   DataArrayIdType *nbPerType=0;
6222   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6223   nbPerType->decrRef();
6224   return tmpa->buildPermArrPerLevel();
6225 }
6226
6227 /*!
6228  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6229  * The number of cells remains unchanged after the call of this method.
6230  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6231  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6232  *
6233  * \return the array giving the correspondence old to new.
6234  */
6235 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6236 {
6237   checkFullyDefined();
6238   computeTypes();
6239   const mcIdType *conn=_nodal_connec->begin();
6240   const mcIdType *connI=_nodal_connec_index->begin();
6241   mcIdType nbOfCells=getNumberOfCells();
6242   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6243   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6244     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6245       {
6246         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6247         types.push_back(curType);
6248         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6249       }
6250   DataArrayIdType *ret=DataArrayIdType::New();
6251   ret->alloc(nbOfCells,1);
6252   mcIdType *retPtr=ret->getPointer();
6253   std::fill(retPtr,retPtr+nbOfCells,-1);
6254   mcIdType newCellId=0;
6255   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6256     {
6257       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6258         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6259           retPtr[std::distance(connI,i)]=newCellId++;
6260     }
6261   renumberCells(retPtr,false);
6262   return ret;
6263 }
6264
6265 /*!
6266  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6267  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6268  * This method makes asumption that connectivity is correctly set before calling.
6269  */
6270 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6271 {
6272   checkConnectivityFullyDefined();
6273   const mcIdType *conn=_nodal_connec->begin();
6274   const mcIdType *connI=_nodal_connec_index->begin();
6275   mcIdType nbOfCells=getNumberOfCells();
6276   std::vector<MEDCouplingUMesh *> ret;
6277   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6278     {
6279       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6280       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6281       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6282       mcIdType endCellId=ToIdType(std::distance(connI,i));
6283       mcIdType sz=endCellId-beginCellId;
6284       mcIdType *cells=new mcIdType[sz];
6285       for(mcIdType j=0;j<sz;j++)
6286         cells[j]=beginCellId+j;
6287       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6288       delete [] cells;
6289       ret.push_back(m);
6290     }
6291   return ret;
6292 }
6293
6294 /*!
6295  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6296  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6297  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6298  *
6299  * \return a newly allocated instance, that the caller must manage.
6300  * \throw If \a this contains more than one geometric type.
6301  * \throw If the nodal connectivity of \a this is not fully defined.
6302  * \throw If the internal data is not coherent.
6303  */
6304 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6305 {
6306   checkConnectivityFullyDefined();
6307   if(_types.size()!=1)
6308     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6309   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6310   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6311   ret->setCoords(getCoords());
6312   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6313   if(retC)
6314     {
6315       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6316       retC->setNodalConnectivity(c);
6317     }
6318   else
6319     {
6320       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6321       if(!retD)
6322         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6323       DataArrayIdType *c=0,*ci=0;
6324       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6325       MCAuto<DataArrayIdType> cs(c),cis(ci);
6326       retD->setNodalConnectivity(cs,cis);
6327     }
6328   return ret.retn();
6329 }
6330
6331 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6332 {
6333   checkConnectivityFullyDefined();
6334   if(_types.size()!=1)
6335     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6336   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6337   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6338   if(cm.isDynamic())
6339     {
6340       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6341       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6342       throw INTERP_KERNEL::Exception(oss.str());
6343     }
6344   mcIdType nbCells=getNumberOfCells();
6345   mcIdType typi=ToIdType(typ);
6346   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6347   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6348   mcIdType *outPtr=connOut->getPointer();
6349   const mcIdType *conn=_nodal_connec->begin();
6350   const mcIdType *connI=_nodal_connec_index->begin();
6351   nbNodesPerCell++;
6352   for(mcIdType i=0;i<nbCells;i++,connI++)
6353     {
6354       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6355         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6356       else
6357         {
6358           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 << ") !";
6359           throw INTERP_KERNEL::Exception(oss.str());
6360         }
6361     }
6362   return connOut.retn();
6363 }
6364
6365 /*!
6366  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6367  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6368  * \param nodalConn nodal connectivity
6369  * \param nodalConnIndex nodal connectivity indices
6370  */
6371 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6372 {
6373   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6374   checkConnectivityFullyDefined();
6375   if(_types.size()!=1)
6376     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6377   mcIdType nbCells=getNumberOfCells(),
6378            lgth=_nodal_connec->getNumberOfTuples();
6379   if(lgth<nbCells)
6380     throw INTERP_KERNEL::Exception(msg0);
6381   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6382   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6383   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6384   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6385   cip[0]=0;
6386   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6387     {
6388       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6389       mcIdType delta(stop-strt);
6390       if(delta>=1)
6391         {
6392           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6393             cp=std::copy(incp+strt,incp+stop,cp);
6394           else
6395             throw INTERP_KERNEL::Exception(msg0);
6396         }
6397       else
6398         throw INTERP_KERNEL::Exception(msg0);
6399       cip[1]=cip[0]+delta;
6400     }
6401   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6402 }
6403
6404 /*!
6405  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6406  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6407  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6408  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6409  * are not used here to avoid the build of big permutation array.
6410  *
6411  * \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
6412  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6413  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6414  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6415  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6416  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6417  * \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
6418  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6419  */
6420 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6421                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6422                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6423 {
6424   std::vector<const MEDCouplingUMesh *> ms2;
6425   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6426     if(*it)
6427       {
6428         (*it)->checkConnectivityFullyDefined();
6429         ms2.push_back(*it);
6430       }
6431   if(ms2.empty())
6432     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6433   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6434   int meshDim=ms2[0]->getMeshDimension();
6435   std::vector<const MEDCouplingUMesh *> m1ssm;
6436   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6437   //
6438   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6439   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6440   mcIdType fake=0,rk=0;
6441   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6442   ret1->alloc(0,1); ret2->alloc(0,1);
6443   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6444     {
6445       if(meshDim!=(*it)->getMeshDimension())
6446         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6447       if(refCoo!=(*it)->getCoords())
6448         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6449       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6450       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6451       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6452       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6453         {
6454           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6455           m1ssmSingleAuto.push_back(singleCell);
6456           m1ssmSingle.push_back(singleCell);
6457           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6458         }
6459     }
6460   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6461   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6462   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6463   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6464     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6465   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6466   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6467   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6468   return ret0.retn();
6469 }
6470
6471 /*!
6472  * This method returns a newly created DataArrayIdType instance.
6473  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6474  */
6475 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6476 {
6477   checkFullyDefined();
6478   const mcIdType *conn=_nodal_connec->begin();
6479   const mcIdType *connIndex=_nodal_connec_index->begin();
6480   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6481   for(const mcIdType *w=begin;w!=end;w++)
6482     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6483       ret->pushBackSilent(*w);
6484   return ret.retn();
6485 }
6486
6487 /*!
6488  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6489  * are in [0:getNumberOfCells())
6490  */
6491 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6492 {
6493   checkFullyDefined();
6494   const mcIdType *conn=_nodal_connec->begin();
6495   const mcIdType *connI=_nodal_connec_index->begin();
6496   mcIdType nbOfCells=getNumberOfCells();
6497   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6498   mcIdType *tmp=new mcIdType[nbOfCells];
6499   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6500     {
6501       mcIdType j=0;
6502       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6503         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6504           tmp[std::distance(connI,i)]=j++;
6505     }
6506   DataArrayIdType *ret=DataArrayIdType::New();
6507   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6508   ret->copyStringInfoFrom(*da);
6509   mcIdType *retPtr=ret->getPointer();
6510   const mcIdType *daPtr=da->begin();
6511   mcIdType nbOfElems=da->getNbOfElems();
6512   for(mcIdType k=0;k<nbOfElems;k++)
6513     retPtr[k]=tmp[daPtr[k]];
6514   delete [] tmp;
6515   return ret;
6516 }
6517
6518 /*!
6519  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6520  * This method \b works \b for mesh sorted by type.
6521  * cells whose ids is in 'idsPerGeoType' array.
6522  * This method conserves coords and name of mesh.
6523  */
6524 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6525 {
6526   std::vector<mcIdType> code=getDistributionOfTypes();
6527   std::size_t nOfTypesInThis=code.size()/3;
6528   mcIdType sz=0,szOfType=0;
6529   for(std::size_t i=0;i<nOfTypesInThis;i++)
6530     {
6531       if(code[3*i]!=type)
6532         sz+=code[3*i+1];
6533       else
6534         szOfType=code[3*i+1];
6535     }
6536   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6537     if(*work<0 || *work>=szOfType)
6538       {
6539         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6540         oss << ". It should be in [0," << szOfType << ") !";
6541         throw INTERP_KERNEL::Exception(oss.str());
6542       }
6543   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6544   mcIdType *idsPtr=idsTokeep->getPointer();
6545   mcIdType offset=0;
6546   for(std::size_t i=0;i<nOfTypesInThis;i++)
6547     {
6548       if(code[3*i]!=type)
6549         for(mcIdType j=0;j<code[3*i+1];j++)
6550           *idsPtr++=offset+j;
6551       else
6552         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6553       offset+=code[3*i+1];
6554     }
6555   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6556   ret->copyTinyInfoFrom(this);
6557   return ret.retn();
6558 }
6559
6560 /*!
6561  * This method returns a vector of size 'this->getNumberOfCells()'.
6562  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6563  */
6564 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6565 {
6566   mcIdType ncell=getNumberOfCells();
6567   std::vector<bool> ret(ncell);
6568   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6569   const mcIdType *c=getNodalConnectivity()->begin();
6570   for(mcIdType i=0;i<ncell;i++)
6571     {
6572       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6573       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6574       ret[i]=cm.isQuadratic();
6575     }
6576   return ret;
6577 }
6578
6579 /*!
6580  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6581  */
6582 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6583 {
6584   if(other->getType()!=UNSTRUCTURED)
6585     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6586   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6587   return MergeUMeshes(this,otherC);
6588 }
6589
6590 /*!
6591  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6592  * computed by averaging coordinates of cell nodes, so this method is not a right
6593  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6594  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6595  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6596  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6597  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6598  *          components. The caller is to delete this array using decrRef() as it is
6599  *          no more needed.
6600  *  \throw If the coordinates array is not set.
6601  *  \throw If the nodal connectivity of cells is not defined.
6602  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6603  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6604  */
6605 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6606 {
6607   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6608   int spaceDim=getSpaceDimension();
6609   mcIdType nbOfCells=getNumberOfCells();
6610   ret->alloc(nbOfCells,spaceDim);
6611   ret->copyStringInfoFrom(*getCoords());
6612   double *ptToFill=ret->getPointer();
6613   const mcIdType *nodal=_nodal_connec->begin();
6614   const mcIdType *nodalI=_nodal_connec_index->begin();
6615   const double *coor=_coords->begin();
6616   for(mcIdType i=0;i<nbOfCells;i++)
6617     {
6618       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6619       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6620       ptToFill+=spaceDim;
6621     }
6622   return ret.retn();
6623 }
6624
6625
6626 /*!
6627  * See computeCellCenterOfMass().
6628  *  \param eps a precision for the detection of degenerated arc of circles.
6629  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6630  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6631  *          components. The caller is to delete this array using decrRef() as it is
6632  *          no more needed.
6633  *  \throw If the coordinates array is not set.
6634  *  \throw If the nodal connectivity of cells is not defined.
6635  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6636  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6637  */
6638 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6639 {
6640   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6641   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6642   return ret.retn();
6643 }
6644
6645
6646 /*!
6647  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6648  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6649  *
6650  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6651  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6652  *
6653  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6654  * \throw If \a this is not fully defined (coordinates and connectivity)
6655  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6656  */
6657 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6658 {
6659   checkFullyDefined();
6660   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6661   int spaceDim=getSpaceDimension();
6662   mcIdType nbOfCells=getNumberOfCells();
6663   mcIdType nbOfNodes=getNumberOfNodes();
6664   ret->alloc(nbOfCells,spaceDim);
6665   double *ptToFill=ret->getPointer();
6666   const mcIdType *nodal=_nodal_connec->begin();
6667   const mcIdType *nodalI=_nodal_connec_index->begin();
6668   const double *coor=_coords->begin();
6669   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6670     {
6671       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6672       std::fill(ptToFill,ptToFill+spaceDim,0.);
6673       if(type!=INTERP_KERNEL::NORM_POLYHED)
6674         {
6675           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6676             {
6677               if(*conn>=0 && *conn<nbOfNodes)
6678                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6679               else
6680                 {
6681                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6682                   throw INTERP_KERNEL::Exception(oss.str());
6683                 }
6684             }
6685           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6686           if(nbOfNodesInCell>0)
6687             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6688           else
6689             {
6690               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6691               throw INTERP_KERNEL::Exception(oss.str());
6692             }
6693         }
6694       else
6695         {
6696           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6697           s.erase(-1);
6698           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6699             {
6700               if(*it>=0 && *it<nbOfNodes)
6701                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6702               else
6703                 {
6704                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6705                   throw INTERP_KERNEL::Exception(oss.str());
6706                 }
6707             }
6708           if(!s.empty())
6709             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6710           else
6711             {
6712               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6713               throw INTERP_KERNEL::Exception(oss.str());
6714             }
6715         }
6716     }
6717   return ret.retn();
6718 }
6719
6720 /*!
6721  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6722  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6723  * are specified via an array of cell ids.
6724  *  \warning Validity of the specified cell ids is not checked!
6725  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6726  *  \param [in] begin - an array of cell ids of interest.
6727  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6728  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6729  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6730  *          caller is to delete this array using decrRef() as it is no more needed.
6731  *  \throw If the coordinates array is not set.
6732  *  \throw If the nodal connectivity of cells is not defined.
6733  *
6734  *  \if ENABLE_EXAMPLES
6735  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6736  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6737  *  \endif
6738  */
6739 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6740 {
6741   DataArrayDouble *ret=DataArrayDouble::New();
6742   int spaceDim=getSpaceDimension();
6743   std::size_t nbOfTuple=std::distance(begin,end);
6744   ret->alloc(nbOfTuple,spaceDim);
6745   double *ptToFill=ret->getPointer();
6746   double *tmp=new double[spaceDim];
6747   const mcIdType *nodal=_nodal_connec->begin();
6748   const mcIdType *nodalI=_nodal_connec_index->begin();
6749   const double *coor=_coords->begin();
6750   for(const mcIdType *w=begin;w!=end;w++)
6751     {
6752       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6753       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6754       ptToFill+=spaceDim;
6755     }
6756   delete [] tmp;
6757   return ret;
6758 }
6759
6760 /*!
6761  * 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".
6762  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6763  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6764  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6765  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6766  *
6767  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6768  * \throw If spaceDim!=3 or meshDim!=2.
6769  * \throw If connectivity of \a this is invalid.
6770  * \throw If connectivity of a cell in \a this points to an invalid node.
6771  */
6772 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6773 {
6774   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6775   mcIdType nbOfCells=getNumberOfCells();
6776   mcIdType nbOfNodes(getNumberOfNodes());
6777   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6778     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6779   ret->alloc(nbOfCells,4);
6780   double *retPtr(ret->getPointer());
6781   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6782   const double *coor(_coords->begin());
6783   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6784     {
6785       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6786       if(nodalI[1]-nodalI[0]>=4)
6787         {
6788           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6789                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6790                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6791           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6792                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6793                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6794           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]};
6795           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]));
6796           for(int j=0;j<3;j++)
6797             {
6798               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6799               if(nodeId>=0 && nodeId<nbOfNodes)
6800                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6801               else
6802                 {
6803                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6804                   throw INTERP_KERNEL::Exception(oss.str());
6805                 }
6806             }
6807           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6808             {
6809               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6810               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6811             }
6812           else
6813             {
6814               if(nodalI[1]-nodalI[0]==4)
6815                 {
6816                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6817                   throw INTERP_KERNEL::Exception(oss.str());
6818                 }
6819               //
6820               double dd[3]={0.,0.,0.};
6821               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6822                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6823               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6824               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6825               std::copy(dd,dd+3,matrix+4*2);
6826               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6827               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6828             }
6829         }
6830       else
6831         {
6832           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6833           throw INTERP_KERNEL::Exception(oss.str());
6834         }
6835     }
6836   return ret.retn();
6837 }
6838
6839 /*!
6840  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6841  *
6842  */
6843 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6844 {
6845   if(!da)
6846     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6847   da->checkAllocated();
6848   std::string name(da->getName());
6849   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6850   if(name.empty())
6851     ret->setName("Mesh");
6852   ret->setCoords(da);
6853   mcIdType nbOfTuples(da->getNumberOfTuples());
6854   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6855   c->alloc(2*nbOfTuples,1);
6856   cI->alloc(nbOfTuples+1,1);
6857   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6858   *cip++=0;
6859   for(mcIdType i=0;i<nbOfTuples;i++)
6860     {
6861       *cp++=INTERP_KERNEL::NORM_POINT1;
6862       *cp++=i;
6863       *cip++=2*(i+1);
6864     }
6865   ret->setConnectivity(c,cI,true);
6866   return ret.retn();
6867 }
6868
6869 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6870 {
6871   if(!da)
6872     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6873   da->checkAllocated();
6874   std::string name(da->getName());
6875   MCAuto<MEDCouplingUMesh> ret;
6876   {
6877     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6878     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6879     arr->alloc(da->getNumberOfTuples());
6880     tmp->setCoordsAt(0,arr);
6881     ret=tmp->buildUnstructured();
6882   }
6883   ret->setCoords(da);
6884   if(name.empty())
6885     ret->setName("Mesh");
6886   else
6887     ret->setName(name);
6888   return ret;
6889 }
6890
6891 /*!
6892  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6893  * Cells and nodes of
6894  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6895  *  \param [in] mesh1 - the first mesh.
6896  *  \param [in] mesh2 - the second mesh.
6897  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6898  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6899  *          is no more needed.
6900  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6901  *  \throw If the coordinates array is not set in none of the meshes.
6902  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6903  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6904  */
6905 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6906 {
6907   std::vector<const MEDCouplingUMesh *> tmp(2);
6908   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6909   return MergeUMeshes(tmp);
6910 }
6911
6912 /*!
6913  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6914  * Cells and nodes of
6915  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6916  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6917  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6918  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6919  *          is no more needed.
6920  *  \throw If \a a.size() == 0.
6921  *  \throw If \a a[ *i* ] == NULL.
6922  *  \throw If the coordinates array is not set in none of the meshes.
6923  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6924  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6925  */
6926 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6927 {
6928   std::size_t sz=a.size();
6929   if(sz==0)
6930     return MergeUMeshesLL(a);
6931   for(std::size_t ii=0;ii<sz;ii++)
6932     if(!a[ii])
6933       {
6934         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6935         throw INTERP_KERNEL::Exception(oss.str());
6936       }
6937   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6938   std::vector< const MEDCouplingUMesh * > aa(sz);
6939   int spaceDim=-3;
6940   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6941     {
6942       const MEDCouplingUMesh *cur=a[i];
6943       const DataArrayDouble *coo=cur->getCoords();
6944       if(coo)
6945         spaceDim=int(coo->getNumberOfComponents());
6946     }
6947   if(spaceDim==-3)
6948     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6949   for(std::size_t i=0;i<sz;i++)
6950     {
6951       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6952       aa[i]=bb[i];
6953     }
6954   return MergeUMeshesLL(aa);
6955 }
6956
6957 /*!
6958  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6959  * dimension and sharing the node coordinates array.
6960  * All cells of the first mesh precede all cells of the second mesh
6961  * within the result mesh.
6962  *  \param [in] mesh1 - the first mesh.
6963  *  \param [in] mesh2 - the second mesh.
6964  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6965  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6966  *          is no more needed.
6967  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6968  *  \throw If the meshes do not share the node coordinates array.
6969  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6970  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6971  */
6972 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6973 {
6974   std::vector<const MEDCouplingUMesh *> tmp(2);
6975   tmp[0]=mesh1; tmp[1]=mesh2;
6976   return MergeUMeshesOnSameCoords(tmp);
6977 }
6978
6979 /*!
6980  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6981  * dimension and sharing the node coordinates array.
6982  * All cells of the *i*-th mesh precede all cells of the
6983  * (*i*+1)-th mesh within the result mesh.
6984  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6985  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6986  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6987  *          is no more needed.
6988  *  \throw If \a a.size() == 0.
6989  *  \throw If \a a[ *i* ] == NULL.
6990  *  \throw If the meshes do not share the node coordinates array.
6991  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6992  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6993  */
6994 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6995 {
6996   if(meshes.empty())
6997     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6998   for(std::size_t ii=0;ii<meshes.size();ii++)
6999     if(!meshes[ii])
7000       {
7001         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7002         throw INTERP_KERNEL::Exception(oss.str());
7003       }
7004   const DataArrayDouble *coords=meshes.front()->getCoords();
7005   int meshDim=meshes.front()->getMeshDimension();
7006   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7007   mcIdType meshLgth=0;
7008   mcIdType meshIndexLgth=0;
7009   for(;iter!=meshes.end();iter++)
7010     {
7011       if(coords!=(*iter)->getCoords())
7012         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7013       if(meshDim!=(*iter)->getMeshDimension())
7014         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7015       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7016       meshIndexLgth+=(*iter)->getNumberOfCells();
7017     }
7018   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7019   nodal->alloc(meshLgth,1);
7020   mcIdType *nodalPtr=nodal->getPointer();
7021   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7022   nodalIndex->alloc(meshIndexLgth+1,1);
7023   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7024   mcIdType offset=0;
7025   for(iter=meshes.begin();iter!=meshes.end();iter++)
7026     {
7027       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7028       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7029       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7030       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7031       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7032       if(iter!=meshes.begin())
7033         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7034       else
7035         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7036       offset+=meshLgth2;
7037     }
7038   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7039   ret->setName("merge");
7040   ret->setMeshDimension(meshDim);
7041   ret->setConnectivity(nodal,nodalIndex,true);
7042   ret->setCoords(coords);
7043   return ret;
7044 }
7045
7046 /*!
7047  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7048  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7049  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7050  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7051  * New" mode are returned for each input mesh.
7052  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7053  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7054  *          valid values [0,1,2], see zipConnectivityTraducer().
7055  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7056  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7057  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7058  *          no more needed.
7059  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7060  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7061  *          is no more needed.
7062  *  \throw If \a meshes.size() == 0.
7063  *  \throw If \a meshes[ *i* ] == NULL.
7064  *  \throw If the meshes do not share the node coordinates array.
7065  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7066  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7067  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7068  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7069  */
7070 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7071 {
7072   //All checks are delegated to MergeUMeshesOnSameCoords
7073   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7074   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7075   corr.resize(meshes.size());
7076   std::size_t nbOfMeshes=meshes.size();
7077   mcIdType offset=0;
7078   const mcIdType *o2nPtr=o2n->begin();
7079   for(std::size_t i=0;i<nbOfMeshes;i++)
7080     {
7081       DataArrayIdType *tmp=DataArrayIdType::New();
7082       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7083       tmp->alloc(curNbOfCells,1);
7084       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7085       offset+=curNbOfCells;
7086       tmp->setName(meshes[i]->getName());
7087       corr[i]=tmp;
7088     }
7089   return ret.retn();
7090 }
7091
7092 /*!
7093  * Makes all given meshes share the nodal connectivity array. The common connectivity
7094  * array is created by concatenating the connectivity arrays of all given meshes. All
7095  * the given meshes must be of the same space dimension but dimension of cells **can
7096  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7097  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7098  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7099  *  \param [in,out] meshes - a vector of meshes to update.
7100  *  \throw If any of \a meshes is NULL.
7101  *  \throw If the coordinates array is not set in any of \a meshes.
7102  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7103  *  \throw If \a meshes are of different space dimension.
7104  */
7105 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7106 {
7107   std::size_t sz=meshes.size();
7108   if(sz==0 || sz==1)
7109     return;
7110   std::vector< const DataArrayDouble * > coords(meshes.size());
7111   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7112   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7113     {
7114       if((*it))
7115         {
7116           (*it)->checkConnectivityFullyDefined();
7117           const DataArrayDouble *coo=(*it)->getCoords();
7118           if(coo)
7119             *it2=coo;
7120           else
7121             {
7122               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7123               oss << " has no coordinate array defined !";
7124               throw INTERP_KERNEL::Exception(oss.str());
7125             }
7126         }
7127       else
7128         {
7129           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7130           oss << " is null !";
7131           throw INTERP_KERNEL::Exception(oss.str());
7132         }
7133     }
7134   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7135   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7136   mcIdType offset=(*it)->getNumberOfNodes();
7137   (*it++)->setCoords(res);
7138   for(;it!=meshes.end();it++)
7139     {
7140       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7141       (*it)->setCoords(res);
7142       (*it)->shiftNodeNumbersInConn(offset);
7143       offset+=oldNumberOfNodes;
7144     }
7145 }
7146
7147 /*!
7148  * Merges nodes coincident with a given precision within all given meshes that share
7149  * the nodal connectivity array. The given meshes **can be of different** mesh
7150  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7151  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7152  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7153  *  \param [in,out] meshes - a vector of meshes to update.
7154  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7155  *  \throw If any of \a meshes is NULL.
7156  *  \throw If the \a meshes do not share the same node coordinates array.
7157  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7158  */
7159 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7160 {
7161   if(meshes.empty())
7162     return ;
7163   std::set<const DataArrayDouble *> s;
7164   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7165     {
7166       if(*it)
7167         s.insert((*it)->getCoords());
7168       else
7169         {
7170           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 !";
7171           throw INTERP_KERNEL::Exception(oss.str());
7172         }
7173     }
7174   if(s.size()!=1)
7175     {
7176       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 !";
7177       throw INTERP_KERNEL::Exception(oss.str());
7178     }
7179   const DataArrayDouble *coo=*(s.begin());
7180   if(!coo)
7181     return;
7182   //
7183   DataArrayIdType *comm,*commI;
7184   coo->findCommonTuples(eps,-1,comm,commI);
7185   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7186   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7187   mcIdType newNbOfNodes;
7188   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7189   if(oldNbOfNodes==newNbOfNodes)
7190     return ;
7191   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7192   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7193     {
7194       (*it)->renumberNodesInConn(o2n->begin());
7195       (*it)->setCoords(newCoords);
7196     }
7197 }
7198
7199
7200 /*!
7201  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7202  */
7203 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7204 {
7205   std::size_t i, ip1;
7206   double v[3]={0.,0.,0.};
7207   std::size_t sz=std::distance(begin,end);
7208   if(!isQuadratic)
7209     for(i=0;i<sz;i++)
7210       {
7211         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7212         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7213         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];
7214         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7215         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7216       }
7217   else
7218     {
7219       // Same algorithm as above but also using intermediate quadratic points.
7220       // (taking only linear points might lead to issues if the linearized version of the
7221       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7222       std::size_t hsz = sz/2;
7223       for(std::size_t j=0;j<sz;j++)
7224         {
7225           if (j%2)  // current point i is quadratic, next point i+1 is standard
7226             {
7227               i = hsz+(j-1)/2;
7228               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7229             }
7230           else      // current point i is standard, next point i+1 is quadratic
7231             {
7232               i = j/2;
7233               ip1 = j/2+hsz;
7234             }
7235           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7236           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7237           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7238         }
7239     }
7240   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7241   return (ret>0.);
7242 }
7243
7244 /*!
7245  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7246  */
7247 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7248 {
7249   std::vector<std::pair<mcIdType,mcIdType> > edges;
7250   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7251   const mcIdType *bgFace=begin;
7252   for(std::size_t i=0;i<nbOfFaces;i++)
7253     {
7254       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7255       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7256       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7257         {
7258           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7259           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7260             return false;
7261           edges.push_back(p1);
7262         }
7263       bgFace=endFace+1;
7264     }
7265   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7266 }
7267
7268 /*!
7269  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7270  */
7271 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7272 {
7273   double vec0[3],vec1[3];
7274   std::size_t sz=std::distance(begin,end);
7275   if(sz%2!=0)
7276     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7277   mcIdType nbOfNodes=ToIdType(sz/2);
7278   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7279   const double *pt0=coords+3*begin[0];
7280   const double *pt1=coords+3*begin[nbOfNodes];
7281   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7282   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7283 }
7284
7285 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7286 {
7287   std::size_t sz=std::distance(begin,end);
7288   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7289   std::size_t nbOfNodes(sz/2);
7290   std::copy(begin,end,(mcIdType *)tmp);
7291   for(std::size_t j=1;j<nbOfNodes;j++)
7292     {
7293       begin[j]=tmp[nbOfNodes-j];
7294       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7295     }
7296 }
7297
7298 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7299 {
7300   std::size_t sz=std::distance(begin,end);
7301   if(sz!=4)
7302     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7303   double vec0[3],vec1[3];
7304   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7305   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];
7306   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;
7307 }
7308
7309 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7310 {
7311   std::size_t sz=std::distance(begin,end);
7312   if(sz!=5)
7313     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7314   double vec0[3];
7315   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7316   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7317   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7318 }
7319
7320 /*!
7321  * 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 )
7322  * 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
7323  * a 2D space.
7324  *
7325  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7326  * \param [in] coords the coordinates with nb of components exactly equal to 3
7327  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7328  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7329  */
7330 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7331                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7332 {
7333   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7334   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7335   double *vPtr=v->getPointer();
7336   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7337   double *pPtr=p->getPointer();
7338   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7339   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7340   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7341     {
7342       mcIdType face = e_f[e_fi[index] + i];
7343       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7344       // to differentiate faces going to different cells:
7345       pPtr++, *pPtr = 0;
7346       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7347         *pPtr += FromIdType<double>(f_e[j]);
7348     }
7349   pPtr=p->getPointer(); vPtr=v->getPointer();
7350   DataArrayIdType *comm1=0,*commI1=0;
7351   v->findCommonTuples(eps,-1,comm1,commI1);
7352   for (mcIdType i = 0; i < nbFaces; i++)
7353     if (comm1->findIdFirstEqual(i) < 0)
7354       {
7355         comm1->pushBackSilent(i);
7356         commI1->pushBackSilent(comm1->getNumberOfTuples());
7357       }
7358   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7359   const mcIdType *comm1Ptr=comm1->begin();
7360   const mcIdType *commI1Ptr=commI1->begin();
7361   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7362   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7363   //
7364   for(mcIdType i=0;i<nbOfGrps1;i++)
7365     {
7366       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7367       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7368       DataArrayIdType *comm2=0,*commI2=0;
7369       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7370       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7371         if (comm2->findIdFirstEqual(j) < 0)
7372           {
7373             comm2->pushBackSilent(j);
7374             commI2->pushBackSilent(comm2->getNumberOfTuples());
7375           }
7376       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7377       const mcIdType *comm2Ptr=comm2->begin();
7378       const mcIdType *commI2Ptr=commI2->begin();
7379       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7380       for(mcIdType j=0;j<nbOfGrps2;j++)
7381         {
7382           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7383             {
7384               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7385               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7386               res->pushBackSilent(-1);
7387             }
7388           else
7389             {
7390               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7391               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7392               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7393               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7394               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7395               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7396               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7397               const mcIdType *idsNodePtr=idsNode->begin();
7398               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];
7399               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7400               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7401               if(std::abs(norm)>eps)
7402                 {
7403                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7404                   mm3->rotate(center,vec,angle);
7405                 }
7406               mm3->changeSpaceDimension(2);
7407               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7408               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7409               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7410               mcIdType nbOfCells=mm4->getNumberOfCells();
7411               for(mcIdType k=0;k<nbOfCells;k++)
7412                 {
7413                   int l=0;
7414                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7415                     res->pushBackSilent(idsNodePtr[*work]);
7416                   res->pushBackSilent(-1);
7417                 }
7418             }
7419         }
7420     }
7421   res->popBackSilent();
7422 }
7423
7424 /*!
7425  * 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
7426  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7427  *
7428  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7429  * \param [in] coords coordinates expected to have 3 components.
7430  * \param [in] begin start of the nodal connectivity of the face.
7431  * \param [in] end end of the nodal connectivity (excluded) of the face.
7432  * \param [out] v the normalized vector of size 3
7433  * \param [out] p the pos of plane
7434  */
7435 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7436 {
7437   std::size_t nbPoints=std::distance(begin,end);
7438   if(nbPoints<3)
7439     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7440   double vec[3]={0.,0.,0.};
7441   std::size_t j=0;
7442   bool refFound=false;
7443   for(;j<nbPoints-1 && !refFound;j++)
7444     {
7445       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7446       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7447       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7448       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7449       if(norm>eps)
7450         {
7451           refFound=true;
7452           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7453         }
7454     }
7455   for(std::size_t i=j;i<nbPoints-1;i++)
7456     {
7457       double curVec[3];
7458       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7459       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7460       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7461       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7462       if(norm<eps)
7463         continue;
7464       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7465       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];
7466       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7467       if(norm>eps)
7468         {
7469           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7470           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7471           return ;
7472         }
7473     }
7474   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7475 }
7476
7477 /*!
7478  * This method tries to obtain a well oriented polyhedron.
7479  * If the algorithm fails, an exception will be thrown.
7480  */
7481 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7482 {
7483   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7484   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7485   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7486   isPerm[0]=true;
7487   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7488   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7489   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7490   //
7491   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7492     {
7493       bgFace=begin;
7494       std::size_t smthChanged=0;
7495       for(std::size_t i=0;i<nbOfFaces;i++)
7496         {
7497           endFace=std::find(bgFace+1,end,-1);
7498           nbOfEdgesInFace=std::distance(bgFace,endFace);
7499           if(!isPerm[i])
7500             {
7501               bool b=false;
7502               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7503                 {
7504                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7505                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7506                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7507                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7508                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7509                 }
7510               if(isPerm[i])
7511                 {
7512                   if(!b)
7513                     std::reverse(bgFace+1,endFace);
7514                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7515                     {
7516                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7517                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7518                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7519                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7520                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7521                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7522                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7523                       if(it!=edgesOK.end())
7524                         {
7525                           edgesOK.erase(it);
7526                           edgesFinished.push_back(p1);
7527                         }
7528                       else
7529                         edgesOK.push_back(p1);
7530                     }
7531                 }
7532             }
7533           bgFace=endFace+1;
7534         }
7535       if(smthChanged==0)
7536         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7537     }
7538   if(!edgesOK.empty())
7539     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7540   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7541     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7542       bgFace=begin;
7543       for(std::size_t i=0;i<nbOfFaces;i++)
7544         {
7545           endFace=std::find(bgFace+1,end,-1);
7546           std::reverse(bgFace+1,endFace);
7547           bgFace=endFace+1;
7548         }
7549     }
7550 }
7551
7552
7553 /*!
7554  * This method makes the assumption spacedimension == meshdimension == 2.
7555  * This method works only for linear cells.
7556  *
7557  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7558  */
7559 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7560 {
7561   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7562     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7563   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7564   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7565   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7566   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7567   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7568   mcIdType nbCells=skin->getNumberOfCells();
7569   if(nbCells==nbOfNodesExpected)
7570     return buildUnionOf2DMeshLinear(skin,n2o);
7571   else if(2*nbCells==nbOfNodesExpected)
7572     return buildUnionOf2DMeshQuadratic(skin,n2o);
7573   else
7574     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7575 }
7576
7577 /*!
7578  * This method makes the assumption spacedimension == meshdimension == 3.
7579  * This method works only for linear cells.
7580  *
7581  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7582  */
7583 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7584 {
7585   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7586     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7587   MCAuto<MEDCouplingUMesh> m=computeSkin();
7588   const mcIdType *conn=m->getNodalConnectivity()->begin();
7589   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7590   mcIdType nbOfCells=m->getNumberOfCells();
7591   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7592   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7593   if(nbOfCells<1)
7594     return ret.retn();
7595   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7596   for(mcIdType i=1;i<nbOfCells;i++)
7597     {
7598       *work++=-1;
7599       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7600     }
7601   return ret.retn();
7602 }
7603
7604 /*!
7605  * \brief Creates a graph of cell neighbors
7606  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7607  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7608  *  For example
7609  *  - index:  0 3 5 6 6
7610  *  - value:  1 2 3 2 3 3
7611  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7612  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7613  */
7614 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7615 {
7616   checkConnectivityFullyDefined();
7617
7618   int meshDim = this->getMeshDimension();
7619   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7620   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7621   this->getReverseNodalConnectivity(revConn,indexr);
7622   const mcIdType* indexr_ptr=indexr->begin();
7623   const mcIdType* revConn_ptr=revConn->begin();
7624
7625   const MEDCoupling::DataArrayIdType* index;
7626   const MEDCoupling::DataArrayIdType* conn;
7627   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7628   index=this->getNodalConnectivityIndex();
7629   mcIdType nbCells=this->getNumberOfCells();
7630   const mcIdType* index_ptr=index->begin();
7631   const mcIdType* conn_ptr=conn->begin();
7632
7633   //creating graph arcs (cell to cell relations)
7634   //arcs are stored in terms of (index,value) notation
7635   // 0 3 5 6 6
7636   // 1 2 3 2 3 3
7637   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7638   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7639
7640   //warning here one node have less than or equal effective number of cell with it
7641   //but cell could have more than effective nodes
7642   //because other equals nodes in other domain (with other global inode)
7643   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7644   std::vector <mcIdType> cell2cell;
7645   cell2cell.reserve(3*nbCells);
7646
7647   for (mcIdType icell=0; icell<nbCells;icell++)
7648     {
7649       std::map<mcIdType,mcIdType > counter;
7650       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7651         {
7652           mcIdType inode=conn_ptr[iconn];
7653           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7654             {
7655               mcIdType icell2=revConn_ptr[iconnr];
7656               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7657               if (iter!=counter.end()) (iter->second)++;
7658               else counter.insert(std::make_pair(icell2,1));
7659             }
7660         }
7661       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7662            iter!=counter.end(); iter++)
7663         if (iter->second >= meshDim)
7664           {
7665             cell2cell_index[icell+1]++;
7666             cell2cell.push_back(iter->first);
7667           }
7668     }
7669   indexr->decrRef();
7670   revConn->decrRef();
7671   cell2cell_index[0]=0;
7672   for (mcIdType icell=0; icell<nbCells;icell++)
7673     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7674
7675   //filling up index and value to create skylinearray structure
7676   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7677   return array;
7678 }
7679
7680
7681 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7682 {
7683   mcIdType nbOfCells=getNumberOfCells();
7684   if(nbOfCells<=0)
7685     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7686   ofs << "  <" << getVTKDataSetType() << ">\n";
7687   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7688   ofs << "      <PointData>\n" << pointData << std::endl;
7689   ofs << "      </PointData>\n";
7690   ofs << "      <CellData>\n" << cellData << std::endl;
7691   ofs << "      </CellData>\n";
7692   ofs << "      <Points>\n";
7693   if(getSpaceDimension()==3)
7694     _coords->writeVTK(ofs,8,"Points",byteData);
7695   else
7696     {
7697       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7698       coo->writeVTK(ofs,8,"Points",byteData);
7699     }
7700   ofs << "      </Points>\n";
7701   ofs << "      <Cells>\n";
7702   const mcIdType *cPtr=_nodal_connec->begin();
7703   const mcIdType *cIPtr=_nodal_connec_index->begin();
7704   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7705   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7706   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7707   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7708   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7709   mcIdType szFaceOffsets=0,szConn=0;
7710   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7711     {
7712       *w2=cPtr[cIPtr[i]];
7713       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7714         {
7715           *w1=-1;
7716           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7717           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7718         }
7719       else
7720         {
7721           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7722           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7723           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7724           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7725           w4=std::copy(c.begin(),c.end(),w4);
7726         }
7727     }
7728   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7729   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7730     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7731   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7732   types->writeVTK(ofs,8,"UInt8","types",byteData);
7733   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7734   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7735   if(szFaceOffsets!=0)
7736     {//presence of Polyhedra
7737       connectivity->reAlloc(szConn);
7738       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7739       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7740       w1=faces->getPointer();
7741       for(mcIdType i=0;i<nbOfCells;i++)
7742         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7743           {
7744             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7745             *w1++=nbFaces;
7746             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7747             for(mcIdType j=0;j<nbFaces;j++)
7748               {
7749                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7750                 *w1++=ToIdType(std::distance(w6,w5));
7751                 w1=std::copy(w6,w5,w1);
7752                 w6=w5+1;
7753               }
7754           }
7755       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7756     }
7757   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7758   ofs << "      </Cells>\n";
7759   ofs << "    </Piece>\n";
7760   ofs << "  </" << getVTKDataSetType() << ">\n";
7761 }
7762
7763 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7764 {
7765   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7766   if(_mesh_dim==-2)
7767     { stream << " Not set !"; return ; }
7768   stream << " Mesh dimension : " << _mesh_dim << ".";
7769   if(_mesh_dim==-1)
7770     return ;
7771   if(!_coords)
7772     { stream << " No coordinates set !"; return ; }
7773   if(!_coords->isAllocated())
7774     { stream << " Coordinates set but not allocated !"; return ; }
7775   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7776   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7777   if(!_nodal_connec_index)
7778     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7779   if(!_nodal_connec_index->isAllocated())
7780     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7781   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7782   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7783   if(cpt!=1 || lgth<1)
7784     return ;
7785   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7786 }
7787
7788 std::string MEDCouplingUMesh::getVTKDataSetType() const
7789 {
7790   return std::string("UnstructuredGrid");
7791 }
7792
7793 std::string MEDCouplingUMesh::getVTKFileExtension() const
7794 {
7795   return std::string("vtu");
7796 }
7797
7798
7799
7800 /**
7801  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7802  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7803  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7804  * The caller is to deal with the resulting DataArrayIdType.
7805  *  \throw If the coordinate array is not set.
7806  *  \throw If the nodal connectivity of the cells is not defined.
7807  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7808  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7809  *
7810  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7811  */
7812 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7813 {
7814   checkFullyDefined();
7815   if(getMeshDimension()!=1)
7816     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7817
7818   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7819   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7820   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7821   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7822   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7823   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7824   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7825   const mcIdType * dsi(_dsi->begin());
7826   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7827   m_points=0;
7828   if (dsii->getNumberOfTuples())
7829     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7830
7831   mcIdType nc=getNumberOfCells();
7832   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7833   result->alloc(nc,1);
7834
7835   // set of edges not used so far
7836   std::set<mcIdType> edgeSet;
7837   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7838
7839   mcIdType startSeg=0;
7840   mcIdType newIdx=0;
7841   // while we have points with only one neighbor segments
7842   do
7843     {
7844       std::list<mcIdType> linePiece;
7845       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7846       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7847         {
7848           // Fill the list forward (resp. backward) from the start segment:
7849           mcIdType activeSeg = startSeg;
7850           mcIdType prevPointId = -20;
7851           mcIdType ptId;
7852           while (!edgeSet.empty())
7853             {
7854               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7855                 {
7856                   if (direction==0)
7857                     linePiece.push_back(activeSeg);
7858                   else
7859                     linePiece.push_front(activeSeg);
7860                   edgeSet.erase(activeSeg);
7861                 }
7862
7863               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7864               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7865               if (dsi[ptId] == 1) // hitting the end of the line
7866                 break;
7867
7868               prevPointId = ptId;
7869               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7870               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7871
7872               //for piecewise meshes made up of closed parts
7873               bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7874               if(segmentAlreadyTreated)
7875                 break;
7876             }
7877         }
7878       // Done, save final piece into DA:
7879       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7880       newIdx += ToIdType(linePiece.size());
7881
7882       // identify next valid start segment (one which is not consumed)
7883       if(!edgeSet.empty())
7884         startSeg = *(edgeSet.begin());
7885
7886     }
7887   while (!edgeSet.empty());
7888   return result.retn();
7889 }
7890
7891 /**
7892  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7893  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7894  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7895  * a minimal creation of new nodes is wanted.
7896  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7897  * nodes if a SEG3 is split without information of middle.
7898  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7899  * avoid to have a non conform mesh.
7900  *
7901  * \return mcIdType - the number of new nodes created (in most of cases 0).
7902  *
7903  * \throw If \a this is not coherent.
7904  * \throw If \a this has not spaceDim equal to 2.
7905  * \throw If \a this has not meshDim equal to 2.
7906  * \throw If some subcells needed to be split are orphan.
7907  * \sa MEDCouplingUMesh::conformize2D
7908  */
7909 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7910 {
7911   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7912     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7913   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7914   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7915     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7916   if(midOpt==0 && midOptI==0)
7917     {
7918       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7919       return 0;
7920     }
7921   else if(midOpt!=0 && midOptI!=0)
7922     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7923   else
7924     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7925 }
7926
7927 /*!
7928  * 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
7929  * 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
7930  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7931  * 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
7932  * 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.
7933  *
7934  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7935  */
7936 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7937 {
7938   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7939   if(sz>=4)
7940     {
7941       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7942       if(cm.getDimension()==2)
7943         {
7944           const mcIdType *node=nodalConnBg+1;
7945           mcIdType startNode=*node++;
7946           double refX=coords[2*startNode];
7947           for(;node!=nodalConnEnd;node++)
7948             {
7949               if(coords[2*(*node)]<refX)
7950                 {
7951                   startNode=*node;
7952                   refX=coords[2*startNode];
7953                 }
7954             }
7955           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7956           refX=1e300;
7957           double tmp1;
7958           double tmp2[2];
7959           double angle0=-M_PI/2;
7960           //
7961           mcIdType nextNode=-1;
7962           mcIdType prevNode=-1;
7963           double resRef;
7964           double angleNext=0.;
7965           while(nextNode!=startNode)
7966             {
7967               nextNode=-1;
7968               resRef=1e300;
7969               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7970                 {
7971                   if(*node!=tmpOut.back() && *node!=prevNode)
7972                     {
7973                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7974                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7975                       double res;
7976                       if(angleM<=angle0)
7977                         res=angle0-angleM;
7978                       else
7979                         res=angle0-angleM+2.*M_PI;
7980                       if(res<resRef)
7981                         {
7982                           nextNode=*node;
7983                           resRef=res;
7984                           angleNext=angleM;
7985                         }
7986                     }
7987                 }
7988               if(nextNode!=startNode)
7989                 {
7990                   angle0=angleNext-M_PI;
7991                   if(angle0<-M_PI)
7992                     angle0+=2*M_PI;
7993                   prevNode=tmpOut.back();
7994                   tmpOut.push_back(nextNode);
7995                 }
7996             }
7997           std::vector<mcIdType> tmp3(2*(sz-1));
7998           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7999           std::copy(nodalConnBg+1,nodalConnEnd,it);
8000           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8001             {
8002               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8003               return false;
8004             }
8005           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8006             {
8007               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8008               return false;
8009             }
8010           else
8011             {
8012               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8013               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8014               return true;
8015             }
8016         }
8017       else
8018         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8019     }
8020   else
8021     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8022 }
8023
8024 /*!
8025  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8026  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8027  * 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]].
8028  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8029  * A negative value in \b arrIn means that it is ignored.
8030  * 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.
8031  *
8032  * \param [in] arrIn arr origin array from which the extraction will be done.
8033  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8034  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8035  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8036  */
8037 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8038 {
8039   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8040   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8041 }
8042
8043 /*!
8044  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8045  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8046  * 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]].
8047  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8048  * A negative value in \b arrIn means that it is ignored.
8049  * 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.
8050  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8051  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8052  * \param [in] arrIn arr origin array from which the extraction will be done.
8053  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8054  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8055  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8056  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8057  * \sa MEDCouplingUMesh::partitionBySpreadZone
8058  */
8059 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8060 {
8061   nbOfDepthPeelingPerformed=0;
8062   if(!arrIndxIn)
8063     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8064   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8065   if(nbOfTuples<=0)
8066     {
8067       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8068       return ret;
8069     }
8070   //
8071   std::vector<bool> fetched(nbOfTuples,false);
8072   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8073 }
8074
8075
8076
8077 /*!
8078  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8079  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8080  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8081  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8082  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8083  *
8084  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8085  */
8086 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8087 {
8088   checkFullyDefined();
8089   int mdim=getMeshDimension();
8090   int spaceDim=getSpaceDimension();
8091   if(mdim!=spaceDim)
8092     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8093   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8094   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8095   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8096   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8097   ret->setCoords(getCoords());
8098   ret->allocateCells(ToIdType(partition.size()));
8099   //
8100   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8101     {
8102       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8103       MCAuto<DataArrayIdType> cell;
8104       switch(mdim)
8105       {
8106         case 2:
8107           cell=tmp->buildUnionOf2DMesh();
8108           break;
8109         case 3:
8110           cell=tmp->buildUnionOf3DMesh();
8111           break;
8112         default:
8113           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8114       }
8115
8116       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8117     }
8118   //
8119   ret->finishInsertingCells();
8120   return ret.retn();
8121 }
8122
8123 /*!
8124  * This method partitions \b this into contiguous zone.
8125  * This method only needs a well defined connectivity. Coordinates are not considered here.
8126  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8127  */
8128 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8129 {
8130   DataArrayIdType *neigh=0,*neighI=0;
8131   computeNeighborsOfCells(neigh,neighI);
8132   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8133   return PartitionBySpreadZone(neighAuto,neighIAuto);
8134 }
8135
8136 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8137 {
8138   if(!arrIn || !arrIndxIn)
8139     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8140   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8141   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8142   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8143     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8144   mcIdType nbOfCellsCur(nbOfTuples-1);
8145   std::vector<DataArrayIdType *> ret;
8146   if(nbOfCellsCur<=0)
8147     return ret;
8148   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8149   std::vector< MCAuto<DataArrayIdType> > ret2;
8150   mcIdType seed=0;
8151   while(seed<nbOfCellsCur)
8152     {
8153       mcIdType nbOfPeelPerformed=0;
8154       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8155       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8156     }
8157   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8158     ret.push_back((*it).retn());
8159   return ret;
8160 }
8161
8162 /*!
8163  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8164  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8165  *
8166  * \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.
8167  * \return a newly allocated DataArrayIdType to be managed by the caller.
8168  * \throw In case of \a code has not the right format (typically of size 3*n)
8169  */
8170 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8171 {
8172   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8173   std::size_t nb=code.size()/3;
8174   if(code.size()%3!=0)
8175     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8176   ret->alloc(nb,2);
8177   mcIdType *retPtr=ret->getPointer();
8178   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8179     {
8180       retPtr[0]=code[3*i+2];
8181       retPtr[1]=code[3*i+2]+code[3*i+1];
8182     }
8183   return ret.retn();
8184 }
8185
8186 /*!
8187  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8188  * All cells in \a this are expected to be linear 3D cells.
8189  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8190  * It leads to an increase to number of cells.
8191  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8192  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8193  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8194  *
8195  * \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.
8196  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8197  * \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.
8198  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8199  *          an id of old cell producing it. The caller is to delete this array using
8200  *         decrRef() as it is no more needed.
8201  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8202  *
8203  * \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
8204  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8205  *
8206  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8207  * \throw If \a this is not fully constituted with linear 3D cells.
8208  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8209  */
8210 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8211 {
8212   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8213   checkConnectivityFullyDefined();
8214   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8215     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8216   mcIdType nbOfCells=getNumberOfCells();
8217   mcIdType nbNodes(getNumberOfNodes());
8218   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8219   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8220   mcIdType *retPt(ret->getPointer());
8221   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8222   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8223   const mcIdType *oldc(_nodal_connec->begin());
8224   const mcIdType *oldci(_nodal_connec_index->begin());
8225   const double *coords(_coords->begin());
8226   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8227     {
8228       std::vector<mcIdType> a; std::vector<double> b;
8229       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8230       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8231       const mcIdType *aa(&a[0]);
8232       if(!b.empty())
8233         {
8234           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8235             if(*it<0)
8236               *it=(-(*(it))-1+nbNodes);
8237           addPts->insertAtTheEnd(b.begin(),b.end());
8238           nbNodes+=ToIdType(b.size()/3);
8239         }
8240       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8241         newConn->insertAtTheEnd(aa,aa+4);
8242     }
8243   if(!addPts->empty())
8244     {
8245       addPts->rearrange(3);
8246       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8247       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8248       ret0->setCoords(addPts);
8249     }
8250   else
8251     {
8252       nbOfAdditionalPoints=0;
8253       ret0->setCoords(getCoords());
8254     }
8255   ret0->setNodalConnectivity(newConn);
8256   //
8257   ret->computeOffsetsFull();
8258   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8259   return ret0.retn();
8260 }
8261
8262 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8263     _own_cell(true),_cell_id(-1),_nb_cell(0)
8264 {
8265   if(mesh)
8266     {
8267       mesh->incrRef();
8268       _nb_cell=mesh->getNumberOfCells();
8269     }
8270 }
8271
8272 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8273 {
8274   if(_mesh)
8275     _mesh->decrRef();
8276   if(_own_cell)
8277     delete _cell;
8278 }
8279
8280 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8281     _own_cell(false),_cell_id(bg-1),
8282     _nb_cell(end)
8283 {
8284   if(mesh)
8285     mesh->incrRef();
8286 }
8287
8288 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8289 {
8290   _cell_id++;
8291   if(_cell_id<_nb_cell)
8292     {
8293       _cell->next();
8294       return _cell;
8295     }
8296   else
8297     return 0;
8298 }
8299
8300 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8301 {
8302   if(_mesh)
8303     _mesh->incrRef();
8304 }
8305
8306 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8307 {
8308   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8309 }
8310
8311 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8312 {
8313   if(_mesh)
8314     _mesh->decrRef();
8315 }
8316
8317 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8318     _itc(itc),
8319     _bg(bg),_end(end)
8320 {
8321   if(_mesh)
8322     _mesh->incrRef();
8323 }
8324
8325 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8326 {
8327   if(_mesh)
8328     _mesh->decrRef();
8329 }
8330
8331 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8332 {
8333   return _type;
8334 }
8335
8336 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8337 {
8338   return _end-_bg;
8339 }
8340
8341 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8342 {
8343   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8344 }
8345
8346 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8347 {
8348   if(mesh)
8349     {
8350       mesh->incrRef();
8351       _nb_cell=mesh->getNumberOfCells();
8352     }
8353 }
8354
8355 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8356 {
8357   if(_mesh)
8358     _mesh->decrRef();
8359   delete _cell;
8360 }
8361
8362 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8363 {
8364   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8365   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8366   if(_cell_id<_nb_cell)
8367     {
8368       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8369       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8370       mcIdType startId=_cell_id;
8371       _cell_id+=nbOfElems;
8372       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8373     }
8374   else
8375     return 0;
8376 }
8377
8378 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8379 {
8380   if(mesh)
8381     {
8382       _conn=mesh->getNodalConnectivity()->getPointer();
8383       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8384     }
8385 }
8386
8387 void MEDCouplingUMeshCell::next()
8388 {
8389   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8390     {
8391       _conn+=_conn_lgth;
8392       _conn_indx++;
8393     }
8394   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8395 }
8396
8397 std::string MEDCouplingUMeshCell::repr() const
8398 {
8399   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8400     {
8401       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8402       oss << " : ";
8403       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8404       return oss.str();
8405     }
8406   else
8407     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8408 }
8409
8410 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8411 {
8412   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8413     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8414   else
8415     return INTERP_KERNEL::NORM_ERROR;
8416 }
8417
8418 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8419 {
8420   lgth=_conn_lgth;
8421   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8422     return _conn;
8423   else
8424     return 0;
8425 }
8426
8427 /// @cond INTERNAL
8428
8429 namespace MEDCouplingImpl
8430 {
8431   const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8432
8433   //================================================================================
8434   /*!
8435    * \brief Encode a cell id and a mesh index into a code
8436    *  \param [in] id - cell id
8437    *  \param [in] iMesh - mesh index [0,1]
8438    *  \return mcIdType - code
8439    */
8440   //================================================================================
8441
8442   mcIdType encodeID( mcIdType id, int iMesh )
8443   {
8444     return ( id + 1 ) * ( iMesh ? -1 : 1 );
8445   }
8446   //================================================================================
8447   /*!
8448    * \brief Return cell id and mesh index by a given id
8449    *  \param [in] id - code of a cell in a mesh
8450    *  \param [out] iMesh - returned mesh index
8451    *  \return mcIdType - cell id
8452    */
8453   //================================================================================
8454
8455   mcIdType decodeID( mcIdType id, int& iMesh )
8456   {
8457     iMesh = ( id < 0 );
8458     return std::abs( id ) - 1;
8459   }
8460
8461   //================================================================================
8462   /*!
8463    * \brief return another face sharing two given nodes of a face edge
8464    *  \param [in] n0 - 1st node of the edge
8465    *  \param [in] n1 - 2nd node of the edge
8466    *  \param [in] inputFaceID - face including \a n0 andf \a n2
8467    *  \param [in] mesh - object and reference meshes
8468    *  \param [in] revNodal - reverse nodal connectivity of the two meshes
8469    *  \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8470    *  \param [out] facesByEdge - return another face including \a n0 andf \a n2
8471    *  \param [out] equalFaces - return faces equal to facesByEdge
8472    */
8473   //================================================================================
8474
8475   void getFacesOfEdge( mcIdType n0,
8476                        mcIdType n1,
8477                        mcIdType inputFaceID,
8478                        MEDCouplingUMesh* mesh[],
8479                        MCAuto<DataArrayIdType> revNodal[],
8480                        MCAuto<DataArrayIdType> revNodalIndx[],
8481                        std::vector< mcIdType >& facesByEdge,
8482                        std::vector< mcIdType >& equalFaces)
8483   {
8484     // find faces sharing the both nodes of edge
8485
8486     facesByEdge.clear();
8487     size_t prevNbF; // nb faces found in 0-th mesh
8488     for ( int iM = 0; iM < 2; ++iM )
8489       {
8490         const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8491         const mcIdType * rev    = revNodal    [ iM ]->begin();
8492
8493         mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8494         mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8495
8496         prevNbF = facesByEdge.size();
8497         facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8498
8499         auto it = std::set_intersection( rev + revInd[ n0 ],
8500                                          rev + revInd[ n0 ] + nbRevFaces0,
8501                                          rev + revInd[ n1 ],
8502                                          rev + revInd[ n1 ] + nbRevFaces1,
8503                                          facesByEdge.begin() + prevNbF );
8504         facesByEdge.resize( it - facesByEdge.begin() );
8505       }
8506
8507     // facesByEdge now contains at least the 'inputFaceID'
8508     // check if there are other faces
8509
8510     size_t nbF = facesByEdge.size();
8511     if ( nbF > 1 )
8512       {
8513         if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8514           {
8515             // remove from facesByEdge equal faces in different meshes
8516             const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8517                                          mesh[1]->getNodalConnectivity()->getConstPointer() };
8518             const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8519                                          mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8520             for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8521               {
8522                 if ( facesByEdge[ i0 ] == theUndefID )
8523                   continue;
8524                 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8525                 bool   isInputFace = ( objFaceID == inputFaceID );
8526
8527                 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8528                   {
8529                     if ( facesByEdge[ i1 ] == theUndefID )
8530                       continue;
8531
8532                     mcIdType f0 = facesByEdge[ i0 ];
8533                     mcIdType f1 = facesByEdge[ i1 ];
8534                     size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8535                     size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8536                     if ( nbNodes0 != nbNodes1 )
8537                       continue;
8538
8539                     const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8540                     const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8541                     if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8542                       {
8543                         // equal faces; remove an object one
8544                         mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8545                         if ( refFaceID == inputFaceID )
8546                           isInputFace = true;
8547
8548                         if ( std::find( equalFaces.begin(),
8549                                         equalFaces.end(), objFaceID ) == equalFaces.end() )
8550                           equalFaces.push_back( objFaceID );
8551
8552                         facesByEdge[ i0 ] = theUndefID;
8553                         if ( isInputFace )
8554                           facesByEdge[ i1 ] = theUndefID;
8555                         break;
8556                       }
8557                   }
8558                 if ( isInputFace )
8559                   facesByEdge[ i0 ] = theUndefID;
8560               }
8561           }
8562       }
8563
8564     nbF = facesByEdge.size();
8565     for ( size_t i = 0; i < facesByEdge.size(); ++i )
8566       {
8567         if ( facesByEdge[ i ] != theUndefID )
8568           {
8569             facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8570             if ( facesByEdge[ i ] == inputFaceID )
8571               facesByEdge[ i ] = theUndefID;
8572           }
8573         nbF -= ( facesByEdge[ i ] == theUndefID );
8574       }
8575
8576     if ( nbF > 1 )
8577       return; // non-manifold
8578
8579     if ( nbF < 1 )
8580       {
8581         facesByEdge.clear();
8582       }
8583     else // nbF == 1, set a found face first
8584       {
8585         if ( facesByEdge[ 0 ] == theUndefID )
8586           {
8587             for ( size_t i = 1; i < facesByEdge.size(); ++i )
8588               if ( facesByEdge[ i ] != theUndefID )
8589                 {
8590                   facesByEdge[ 0 ] = facesByEdge[ i ];
8591                   break;
8592                 }
8593           }
8594         facesByEdge.resize( 1 );
8595       }
8596     return;
8597   }
8598
8599   //================================================================================
8600   /*!
8601    * \brief Remove a face from nodal reversed connectivity
8602    *  \param [in] node - a node of the face
8603    *  \param [in] face - the face
8604    *  \param [in.out] revNodal - reverse nodal connectivity
8605    *  \param [in,out] revNodalIndx - reverse nodal connectivity index
8606    */
8607   //================================================================================
8608
8609   void removeFromRevNodal( mcIdType node,
8610                            mcIdType face,
8611                            MCAuto<DataArrayIdType>& revNodal,
8612                            MCAuto<DataArrayIdType>& revNodalIndx)
8613   {
8614     mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8615     mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8616     auto it = std::find( fBeg, fEnd, face );
8617     if ( it != fEnd )
8618       {
8619         for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8620           *( it2 - 1 ) = *it2;
8621
8622         *( fEnd - 1 ) = theUndefID;
8623       }
8624   }
8625
8626   //================================================================================
8627   /*!
8628    * \brief Check order of two nodes in a given face
8629    *  \param [inout] n0 - node 1
8630    *  \param [inout] n1 - node 2
8631    *  \param [inout] iFEnc - face
8632    *  \param [inout] mesh - mesh
8633    *  \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8634    */
8635   //================================================================================
8636
8637   bool isReverseOrder( mcIdType n0,
8638                        mcIdType n1,
8639                        mcIdType iFEnc,
8640                        MEDCouplingUMesh* mesh[] )
8641   {
8642     int iMesh;
8643     mcIdType iF = decodeID( iFEnc, iMesh );
8644
8645     const mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8646     const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8647
8648     auto it0 = std::find( conn + connI[ iF ] + 1,
8649                           conn + connI[ iF + 1 ],
8650                           n0 );
8651     auto it1 = std::find( conn + connI[ iF ] + 1,
8652                           conn + connI[ iF + 1 ],
8653                           n1 );
8654     long i0 = it0 - conn;
8655     long i1 = it1 - conn;
8656
8657     bool isRev = ( std::abs( i1 - i0 ) == 1 ) ?  i1 < i0 :  i0 < i1;
8658     return isRev;
8659   }
8660
8661   //================================================================================
8662   /*!
8663    * \brief Change orientation of a face in one of given meshes
8664    *  \param [in] iFEnc - face ID also encoding a mesh index
8665    *  \param [in,out] mesh - object and reference meshes
8666    */
8667   //================================================================================
8668
8669   void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8670   {
8671     int iMesh;
8672     mcIdType face = decodeID( iFEnc, iMesh );
8673
8674     mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8675     mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8676
8677     const INTERP_KERNEL::CellModel& cm =
8678       INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8679
8680     cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8681                               (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8682     return;
8683   }
8684 }
8685
8686 /// @endcond
8687
8688 //================================================================================
8689 /*!
8690  * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8691  *  \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8692  *              If there are no cells in \a refFaces or it is nullptr, then any face
8693  *              in \a this mesh is used as a reference
8694  *  \throw If \a this mesh is not well defined.
8695  *  \throw If \a this mesh or \refFaces are not 2D.
8696  *  \throw If \a this mesh and \refFaces do not share nodes.
8697  *  \throw If \a refFaces are not equally oriented.
8698  *  \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8699  *
8700  *  \if ENABLE_EXAMPLES
8701  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8702  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8703  *  \endif
8704  */
8705 //================================================================================
8706
8707 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8708 {
8709   checkConsistencyLight();
8710   if ( getMeshDimension() != 2 )
8711     throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8712   if ( refFaces )
8713     {
8714       refFaces->checkConsistencyLight();
8715       if ( refFaces->getMeshDimension() != 2 )
8716         throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8717       if ( getCoords() != refFaces->getCoords() )
8718         throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8719       if ( refFaces->getNumberOfCells() == 0 )
8720         refFaces = nullptr;
8721     }
8722   if ( getNumberOfCells() == 0 )
8723     return;
8724
8725   enum { _OBJ, _REF };
8726   MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8727   MCAuto<MEDCouplingUMesh> meshPtr;
8728   if ( !mesh[_REF] )
8729     {
8730       meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8731       mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8732       mesh[_REF]->allocateCells(0);
8733       mesh[_REF]->finishInsertingCells();
8734     }
8735   mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8736                                  mesh[_REF]->getNumberOfCells() };
8737   std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8738   isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8739   isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8740
8741   MCAuto<DataArrayIdType> revNodal    [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8742   MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8743   mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8744   mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8745
8746   std::vector< mcIdType > faceNodes(4);
8747   std::vector< mcIdType > facesByEdge(4), equalFaces;
8748   std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8749
8750   while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8751     {
8752       if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8753         {
8754           for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8755             if ( nbFacesToCheck[iMesh] > 0 )
8756               for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8757                 if ( !isFaceQueued[iMesh][f] )
8758                   {
8759                     faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8760                     isFaceQueued[ iMesh ][ f ] = true;
8761                     iMesh = 0;
8762                     break;
8763                   }
8764           if ( faceQueue.empty() )
8765             break;
8766         }
8767
8768       mcIdType fID = faceQueue.back();
8769       faceQueue.pop_back();
8770
8771       int iMesh, iMesh2;
8772       mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8773
8774       nbFacesToCheck[iMesh]--;
8775
8776       equalFaces.clear();
8777       faceNodes.clear();
8778       mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8779       const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8780       const int nbEdges = cm.getNumberOfSons();
8781
8782       // loop on edges of the refFace
8783       mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8784       for ( int edge = 0; edge < nbEdges; ++edge )
8785         {
8786           mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8787
8788           // get faces sharing the edge
8789           MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8790                                            facesByEdge, equalFaces );
8791
8792           if ( facesByEdge.size() > 1 )
8793             THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8794
8795           if ( facesByEdge.size() == 1 )
8796             {
8797               // compare orientation of two faces
8798               //
8799               if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8800                 {
8801                   if ( facesByEdge[0] < 0 ) // in the ref mesh
8802                     throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8803
8804                   MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8805                 }
8806               mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8807               if ( !isFaceQueued[iMesh2][face2] )
8808                 {
8809                   isFaceQueued[iMesh2][face2] = true;
8810                   faceQueue.push_back( facesByEdge[0] );
8811                 }
8812             }
8813           n0 = n1;
8814         }
8815
8816       // remove face and equalFaces from revNodal in order not to treat them again
8817       equalFaces.push_back( fID );
8818       for ( mcIdType face : equalFaces )
8819         {
8820           mcIdType f            = MEDCouplingImpl::decodeID( face, iMesh2 );
8821           const mcIdType *conn  = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8822           const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8823           mcIdType nbNodes      = connI[ f + 1 ] - connI[ f ] - 1;
8824           for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8825
8826             MEDCouplingImpl::removeFromRevNodal( *n, f,  // not to treat f again
8827                                                  revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8828         }
8829
8830     } // while() until all faces checked
8831
8832   return;
8833 }