Salome HOME
refactor!: remove adm_local/ directory
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2024  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * This method is a generalization of buildDescendingConnectivity method. This method return mesh containing subcells of this at level specified by \a targetDeltaLevel
702  * and return descending and reverse descending correspondances to this.
703  *
704  * \param [in] targetDeltaLevel target delta level compared to \a this mesh dimension. This parameter is expected to be lower than zero.
705  * 
706  * \throw If targetDeltaLevel is greater or equal to zero
707  * \throw If targetDeltaLevel is lower than -meshDim
708  * \sa MEDCouplingUMesh::buildDescendingConnectivity, MEDCouplingUMesh::explode3DMeshTo1D
709  */
710 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeMeshTo(int targetDeltaLevel, MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndx, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
711 {
712   this->checkConsistencyLight();
713   if( targetDeltaLevel >= 0 )
714     THROW_IK_EXCEPTION("Input parameter targetDeltaLevel is expected to be lower than zero !");
715   if( targetDeltaLevel == -1 )
716   {
717     desc = DataArrayIdType::New(); descIndx = DataArrayIdType::New(); revDesc = DataArrayIdType::New(); revDescIndx = DataArrayIdType::New();
718     MCAuto<MEDCouplingUMesh> ret( this->buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx) );
719     return ret;
720   }
721   if( targetDeltaLevel == -2 && this->getMeshDimension() == 3 )
722   {
723     desc = DataArrayIdType::New(); descIndx = DataArrayIdType::New(); revDesc = DataArrayIdType::New(); revDescIndx = DataArrayIdType::New();
724     MCAuto<MEDCouplingUMesh> ret( this->explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx) );
725     return ret;
726   }
727   if( targetDeltaLevel == -this->getMeshDimension() )
728   {
729     MCAuto<MEDCouplingUMesh> ret = MEDCouplingUMesh::Build0DMeshFromCoords( const_cast<DataArrayDouble *>( this->getCoords() ) );
730     MEDCouplingUMesh::DeleteCellTypeInIndexedArray(getNodalConnectivity(),getNodalConnectivityIndex(),desc,descIndx);
731     revDesc = DataArrayIdType::New(); revDescIndx = DataArrayIdType::New();
732     this->getReverseNodalConnectivity(revDesc,revDescIndx);
733     return ret;
734   }
735   THROW_IK_EXCEPTION("Not valid input targetDeltaLevel regarding mesh dimension");
736 }
737
738 /*!
739  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
740  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
741  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
742  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
743  * \sa MEDCouplingUMesh::buildDescendingConnectivity
744  */
745 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
746 {
747   checkFullyDefined();
748   if(getMeshDimension()!=3)
749     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
750   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
751 }
752
753 /*!
754  * 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.
755  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
756  * 
757  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
758  */
759 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
760 {
761    checkFullyDefined();
762    switch(getMeshDimension())
763      {
764      case 2:
765        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
766      case 3:
767        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
768      default:
769        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
770      }
771 }
772
773 /*!
774  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
775  * this->getMeshDimension(), that bound cells of \a this mesh. In
776  * addition arrays describing correspondence between cells of \a this and the result
777  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
778  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
779  *  mesh. This method differs from buildDescendingConnectivity() in that apart
780  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
781  * result meshes. So a positive id means that order of nodes in corresponding cells
782  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
783  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
784  * i.e. cell ids are one-based.
785  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
786  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
787  * \warning For speed reasons, this method does not check if node ids in the nodal
788  *          connectivity correspond to the size of node coordinates array.
789  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
790  *          to write this mesh to the MED file, its cells must be sorted using
791  *          sortCellsInMEDFileFrmt().
792  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
793  *         each cell of \a this mesh.
794  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
795  *        dividing cell ids in \a desc into groups each referring to one
796  *        cell of \a this mesh. Its every element (except the last one) is an index
797  *        pointing to the first id of a group of cells. For example cells of the
798  *        result mesh bounding the cell #1 of \a this mesh are described by following
799  *        range of indices:
800  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
801  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
802  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
803  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
804  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
805  *         by each cell of the result mesh.
806  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
807  *        in the result mesh,
808  *        dividing cell ids in \a revDesc into groups each referring to one
809  *        cell of the result mesh the same way as \a descIndx divides \a desc.
810  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
811  *        shares the node coordinates array with \a this mesh. The caller is to
812  *        delete this mesh using decrRef() as it is no more needed.
813  *  \throw If the coordinates array is not set.
814  *  \throw If the nodal connectivity of cells is node defined.
815  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
816  *         revDescIndx == NULL.
817  *
818  *  \if ENABLE_EXAMPLES
819  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
820  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
821  *  \endif
822  * \sa buildDescendingConnectivity()
823  */
824 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
825 {
826   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
827 }
828
829 /*!
830  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
831  * For speed reasons no check of this will be done. This method calls
832  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
833  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
834  * only connectivities are considered.
835  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
836  * The format of return is hence \ref numbering-indirect.
837  *
838  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
839  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
840  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
841  * is equal to the last values in \b neighborsIndx.
842  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
843  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
844  */
845 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
846 {
847   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
848   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
849   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
850   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
851   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
852   meshDM1=0;
853   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
854 }
855
856 /**
857  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
858  * 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
859  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
860  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
861  *
862  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
863  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
864  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
865  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
866  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
867  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
868  *
869  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
870  */
871 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
872                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
873 {
874   if(!nodeNeigh || !nodeNeighI)
875     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
876   checkConsistencyLight();
877   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
878   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
879   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
880   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
881   mcIdType nbCells=getNumberOfCells();
882   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
883   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
884   for(mcIdType i=0;i<nbCells;i++)
885     {
886       std::set<mcIdType> s;
887       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
888         if(*it>=0)  // avoid -1 in polygons or polyedrons
889           s.insert(ne+nei[*it],ne+nei[*it+1]);
890       s.erase(i);
891       cellNeigh->insertAtTheEnd(s.begin(),s.end());
892       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
893     }
894 }
895
896 /*!
897  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
898  * of MEDCouplingUMesh::computeNeighborsOfCells.
899  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
900  * typically the case to extract a set a neighbours,
901  * excluding a set of meshdim-1 cells in input descending connectivity.
902  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
903  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
904  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
905  * are considered.
906  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
907  *
908  * \param [in] desc descending connectivity array.
909  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
910  * \param [in] revDesc reverse descending connectivity array.
911  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
912  * \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
913  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
914  * \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.
915  */
916 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
917                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
918 {
919   if(!desc || !descIndx || !revDesc || !revDescIndx)
920     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
921   const mcIdType *descPtr=desc->begin();
922   const mcIdType *descIPtr=descIndx->begin();
923   const mcIdType *revDescPtr=revDesc->begin();
924   const mcIdType *revDescIPtr=revDescIndx->begin();
925   //
926   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
927   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
928   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
929   mcIdType *out1Ptr=out1->getPointer();
930   *out1Ptr++=0;
931   out0->reserve(desc->getNumberOfTuples());
932   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
933     {
934       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
935         {
936           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
937           s.erase(i);
938           out0->insertAtTheEnd(s.begin(),s.end());
939         }
940       *out1Ptr=out0->getNumberOfTuples();
941     }
942   neighbors=out0.retn();
943   neighborsIndx=out1.retn();
944 }
945
946 /*!
947  * Explodes \a this into edges whatever its dimension.
948  */
949 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
950 {
951   checkFullyDefined();
952   int mdim(getMeshDimension());
953   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
954   MCAuto<MEDCouplingUMesh> mesh1D;
955   switch(mdim)
956   {
957     case 3:
958       {
959         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
960         break;
961       }
962     case 2:
963       {
964         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
965         break;
966       }
967     default:
968       {
969         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
970       }
971   }
972   return mesh1D;
973 }
974
975 /*!
976  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
977  * For speed reasons no check of this will be done. This method calls
978  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
979  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
980  * only connectivities are considered.
981  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
982  *
983  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
984  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
985  * parameter allows to select the right part in this array (\ref numbering-indirect).
986  * The number of tuples is equal to the last values in \b neighborsIndx.
987  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
988  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
989  *
990  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
991  */
992 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
993 {
994   checkFullyDefined();
995   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
996   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
997   MCConstAuto<MEDCouplingUMesh> mesh1D;
998   switch(mdim)
999   {
1000     case 3:
1001       {
1002         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
1003         break;
1004       }
1005     case 2:
1006       {
1007         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
1008         break;
1009       }
1010     case 1:
1011       {
1012         mesh1D.takeRef(this);
1013         break;
1014       }
1015     default:
1016       {
1017         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
1018       }
1019   }
1020   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
1021   mesh1D->getReverseNodalConnectivity(desc,descIndx);
1022   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
1023   ret0->alloc(desc->getNumberOfTuples(),1);
1024   mcIdType *r0Pt(ret0->getPointer());
1025   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
1026   for(mcIdType i=0;i<nbNodes;i++,rni++)
1027     {
1028       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
1029         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
1030     }
1031   neighbors=ret0.retn();
1032   neighborsIdx=descIndx.retn();
1033 }
1034
1035 /*!
1036  * 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.
1037  * 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.
1038  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1039  *
1040  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1041  */
1042 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1043 {
1044   checkFullyDefined();
1045   mcIdType nbOfNodes(getNumberOfNodes());
1046   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1047   mcIdType nbOfCells=getNumberOfCells();
1048   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1049   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1050     {
1051       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1052       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1053       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1054         st0[*iter2].insert(s.begin(),s.end());
1055     }
1056   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1057   {
1058     mcIdType *neighIdx(neighborsIdx->getPointer());
1059     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1060       {
1061         if ((*it).empty())
1062           neighIdx[1]=neighIdx[0];
1063         else
1064           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1065       }
1066   }
1067   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1068   {
1069     const mcIdType *neighIdx(neighborsIdx->begin());
1070     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1071     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1072       {
1073         std::set<mcIdType> s(*it); s.erase(nodeId);
1074         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1075       }
1076   }
1077 }
1078
1079 /*!
1080  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1081  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1082  * array of cell ids. Pay attention that after conversion all algorithms work slower
1083  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1084  * conversion due presence of invalid ids in the array of cells to convert, as a
1085  * result \a this mesh contains some already converted elements. In this case the 2D
1086  * mesh remains valid but 3D mesh becomes \b inconsistent!
1087  *  \warning This method can significantly modify the order of geometric types in \a this,
1088  *          hence, to write this mesh to the MED file, its cells must be sorted using
1089  *          sortCellsInMEDFileFrmt().
1090  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1091  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1092  *         cellIdsToConvertBg.
1093  *  \throw If the coordinates array is not set.
1094  *  \throw If the nodal connectivity of cells is node defined.
1095  *  \throw If dimension of \a this mesh is not either 2 or 3.
1096  *
1097  *  \if ENABLE_EXAMPLES
1098  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1099  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1100  *  \endif
1101  */
1102 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1103 {
1104   checkFullyDefined();
1105   int dim=getMeshDimension();
1106   if(dim<2 || dim>3)
1107     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1108   mcIdType nbOfCells=getNumberOfCells();
1109   if(dim==2)
1110     {
1111       const mcIdType *connIndex=_nodal_connec_index->begin();
1112       mcIdType *conn=_nodal_connec->getPointer();
1113       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1114         {
1115           if(*iter>=0 && *iter<nbOfCells)
1116             {
1117               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1118               if(!cm.isQuadratic())
1119                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1120               else
1121                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1122             }
1123           else
1124             {
1125               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1126               oss << " in range [0," << nbOfCells << ") !";
1127               throw INTERP_KERNEL::Exception(oss.str());
1128             }
1129         }
1130     }
1131   else
1132     {
1133       mcIdType *connIndex(_nodal_connec_index->getPointer());
1134       const mcIdType *connOld(_nodal_connec->getConstPointer());
1135       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1136       std::vector<bool> toBeDone(nbOfCells,false);
1137       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1138         {
1139           if(*iter>=0 && *iter<nbOfCells)
1140             toBeDone[*iter]=true;
1141           else
1142             {
1143               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1144               oss << " in range [0," << nbOfCells << ") !";
1145               throw INTERP_KERNEL::Exception(oss.str());
1146             }
1147         }
1148       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1149         {
1150           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1151           mcIdType lgthOld(posP1-pos-1);
1152           if(toBeDone[cellId])
1153             {
1154               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1155               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1156               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1157               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1158               for(unsigned j=0;j<nbOfFaces;j++)
1159                 {
1160                   INTERP_KERNEL::NormalizedCellType type;
1161                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1162                   work+=offset;
1163                   *work++=-1;
1164                 }
1165               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1166               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1167               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1168               delete [] tmp;
1169             }
1170           else
1171             {
1172               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1173               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1174             }
1175         }
1176       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1177     }
1178   computeTypes();
1179 }
1180
1181 /*!
1182  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1183  * polyhedrons (if \a this is a 3D mesh).
1184  *  \warning As this method is purely for user-friendliness and no optimization is
1185  *          done to avoid construction of a useless vector, this method can be costly
1186  *          in memory.
1187  *  \throw If the coordinates array is not set.
1188  *  \throw If the nodal connectivity of cells is node defined.
1189  *  \throw If dimension of \a this mesh is not either 2 or 3.
1190  */
1191 void MEDCouplingUMesh::convertAllToPoly()
1192 {
1193   mcIdType nbOfCells=getNumberOfCells();
1194   std::vector<mcIdType> cellIds(nbOfCells);
1195   for(mcIdType i=0;i<nbOfCells;i++)
1196     cellIds[i]=i;
1197   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1198 }
1199
1200 /*!
1201  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1202  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1203  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1204  * base facet of the volume and the second half of nodes describes an opposite facet
1205  * having the same number of nodes as the base one. This method converts such
1206  * connectivity to a valid polyhedral format where connectivity of each facet is
1207  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1208  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1209  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1210  * a correct orientation of the first facet of a polyhedron, else orientation of a
1211  * corrected cell is reverse.<br>
1212  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1213  * it releases the user from boring description of polyhedra connectivity in the valid
1214  * format.
1215  *  \throw If \a this->getMeshDimension() != 3.
1216  *  \throw If \a this->getSpaceDimension() != 3.
1217  *  \throw If the nodal connectivity of cells is not defined.
1218  *  \throw If the coordinates array is not set.
1219  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1220  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1221  *
1222  *  \if ENABLE_EXAMPLES
1223  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1224  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1225  *  \endif
1226  */
1227 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1228 {
1229   checkFullyDefined();
1230   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1231     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1232   mcIdType nbOfCells=getNumberOfCells();
1233   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1234   newCi->alloc(nbOfCells+1,1);
1235   mcIdType *newci=newCi->getPointer();
1236   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1237   const mcIdType *c=_nodal_connec->getConstPointer();
1238   newci[0]=0;
1239   for(mcIdType i=0;i<nbOfCells;i++)
1240     {
1241       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1242       if(type==INTERP_KERNEL::NORM_POLYHED)
1243         {
1244           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1245             {
1246               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1247               throw INTERP_KERNEL::Exception(oss.str());
1248             }
1249           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1250           if(n2%2!=0)
1251             {
1252               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 !";
1253               throw INTERP_KERNEL::Exception(oss.str());
1254             }
1255           mcIdType n1=ToIdType(n2/2);
1256           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)
1257         }
1258       else
1259         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1260     }
1261   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1262   newC->alloc(newci[nbOfCells],1);
1263   mcIdType *newc=newC->getPointer();
1264   for(mcIdType i=0;i<nbOfCells;i++)
1265     {
1266       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1267       if(type==INTERP_KERNEL::NORM_POLYHED)
1268         {
1269           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1270           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1271           *newc++=-1;
1272           for(std::size_t j=0;j<n1;j++)
1273             {
1274               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1275               newc[n1+5*j]=-1;
1276               newc[n1+5*j+1]=c[ci[i]+1+j];
1277               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1278               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1279               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1280             }
1281           newc+=n1*6;
1282         }
1283       else
1284         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1285     }
1286   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1287   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1288 }
1289
1290
1291 /*!
1292  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1293  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1294  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1295  *          to write this mesh to the MED file, its cells must be sorted using
1296  *          sortCellsInMEDFileFrmt().
1297  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1298  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1299  * \return \c true if at least one cell has been converted, \c false else. In the
1300  *         last case the nodal connectivity remains unchanged.
1301  * \throw If the coordinates array is not set.
1302  * \throw If the nodal connectivity of cells is not defined.
1303  * \throw If \a this->getMeshDimension() < 0.
1304  */
1305 bool MEDCouplingUMesh::unPolyze()
1306 {
1307   checkFullyDefined();
1308   int mdim=getMeshDimension();
1309   if(mdim<0)
1310     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1311   if(mdim<=1)
1312     return false;
1313   mcIdType nbOfCells=getNumberOfCells();
1314   if(nbOfCells<1)
1315     return false;
1316   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1317   mcIdType *conn=_nodal_connec->getPointer();
1318   mcIdType *index=_nodal_connec_index->getPointer();
1319   mcIdType posOfCurCell=0;
1320   mcIdType newPos=0;
1321   mcIdType lgthOfCurCell;
1322   bool ret=false;
1323   for(mcIdType i=0;i<nbOfCells;i++)
1324     {
1325       lgthOfCurCell=index[i+1]-posOfCurCell;
1326       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1327       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1328       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1329       mcIdType newLgth=0;
1330       if(cm.isDynamic())
1331         {
1332           switch(cm.getDimension())
1333           {
1334             case 2:
1335               {
1336                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1337                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1338                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1339                 break;
1340               }
1341             case 3:
1342               {
1343                 mcIdType nbOfFaces,lgthOfPolyhConn;
1344                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1345                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1346                 break;
1347               }
1348          /*   case 1:  // Not supported yet
1349               {
1350                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1351                 break;
1352               }
1353          */
1354           }
1355           ret=ret || (newType!=type);
1356           conn[newPos]=newType;
1357           newPos+=newLgth+1;
1358           posOfCurCell=index[i+1];
1359           index[i+1]=newPos;
1360         }
1361       else
1362         {
1363           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1364           newPos+=lgthOfCurCell;
1365           posOfCurCell+=lgthOfCurCell;
1366           index[i+1]=newPos;
1367         }
1368     }
1369   if(newPos!=initMeshLgth)
1370     _nodal_connec->reAlloc(newPos);
1371   if(ret)
1372     computeTypes();
1373   return ret;
1374 }
1375
1376 /*!
1377  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1378  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1379  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1380  *
1381  * \b WARNING: this method will not modify edges connectivity! Take a look at colinearizeEdges for that.
1382  *
1383  * \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
1384  *             precision.
1385  */
1386 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1387 {
1388   checkFullyDefined();
1389   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1390     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1391   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1392   coords->recenterForMaxPrecision(eps);
1393   //
1394   mcIdType nbOfCells=getNumberOfCells();
1395   const mcIdType *conn=_nodal_connec->getConstPointer();
1396   const mcIdType *index=_nodal_connec_index->getConstPointer();
1397   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1398   connINew->alloc(nbOfCells+1,1);
1399   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1400   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1401   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1402   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1403   bool changed=false;
1404   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1405     {
1406       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1407         {
1408           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1409           changed=true;
1410         }
1411       else
1412         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1413       *connINewPtr=connNew->getNumberOfTuples();
1414     }
1415   if(changed)
1416     setConnectivity(connNew,connINew,false);
1417 }
1418
1419 /*!
1420  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1421  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1422  * This method allows to simplify edges of polyhedron cells so that consecutive colinear segments (with intermediate points
1423  * not used by any other cell) are merged together.
1424  *
1425  * \param [in] eps is a relative precision that allows to establish if two consecutive 3D segments are colinear or not.
1426  *
1427  * \sa simplifyPolyhedra
1428  */
1429 void MEDCouplingUMesh::colinearizeEdges(double eps)
1430 {
1431   //
1432   // Thanks to Antoine Gerschenfeld (CEA) for contributing this method!
1433   //
1434   using DAI = MCAuto<DataArrayIdType>;
1435   checkFullyDefined();
1436   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearizeEdges() : works with meshdim=3 and spaceDim=3!");
1438   double seps = sqrt(1-eps);
1439   // Computing connectivities and correspondances : elements -> segments -> points
1440   DAI E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New()),
1441          F_Si(DataArrayIdType::New()), F_S(DataArrayIdType::New()), S_Fi(DataArrayIdType::New()), S_F(DataArrayIdType::New()),
1442          S_Pi(DataArrayIdType::New()), S_P(DataArrayIdType::New()), P_Si(DataArrayIdType::New()), P_S(DataArrayIdType::New());
1443   MCAuto<MEDCouplingUMesh> m_f(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei)),
1444          m_s(m_f->buildDescendingConnectivity(F_S, F_Si, S_F, S_Fi)),
1445          m_p(m_s->buildDescendingConnectivity(S_P, S_Pi, P_S, P_Si)); // E: elem, F: faces, S: segments (edges), P: points (vertices)
1446   const mcIdType *S_Pp(S_P->begin()), *S_Pip(S_Pi->begin()), *P_Sp(P_S->begin()), *P_Sip(P_Si->begin());
1447   std::set<mcIdType> pt_rem;
1448   const mcIdType *m_pi = m_p->getNodalConnectivityIndex()->begin(),
1449                  *m_pc = m_p->getNodalConnectivity()->begin();
1450   double (*coord)[3] = (double (*)[3]) getCoords()->begin();
1451   // Find all points only connected to exaclty 2 segments - they are the candidates for elimination
1452   // Note that in 3D this can only happen for polyhedrons (when this happens at all)
1453   DAI dsi = P_Si->deltaShiftIndex();
1454   DAI cand = dsi->findIdsEqual(2);
1455   for (const mcIdType& i: *cand)  // i is a point to be potentially eliminated, shared by 2 segs only
1456     {
1457       double n2[2] = {0., 0.}, scal = 0.; // n2 is a squared norm, scal is a scalar product
1458       mcIdType p[2][2];                   // p[j][k] is the ID (in the coord array) of the k-th point of the j-th segment
1459       for (mcIdType j = 0; j < 2; j++)
1460         for (mcIdType k = 0; k < 2; k++)
1461           {
1462             mcIdType off1 = P_Sip[i] + j;   // offset to get ID of the j-th seg (around the i-th point) in the point->seg correspondance
1463             mcIdType pt_id = P_Sp[off1] + k; // ID of the k-th point of the j-th seg in the point->seg correspondance
1464             mcIdType pt_id2 = S_Pp[S_Pip[pt_id]]; // ID of the point in the point mesh
1465             p[j][k] = m_pc[m_pi[pt_id2] + 1];  // Absolute ID, as read from the connectvity (+1 to skip type: NORM_POINT1)
1466             // Just for fun, as initially written by Antoine :-)
1467             // p[j][k] = m_pc[m_pi[S_P->getIJ(S_Pi->getIJ(P_S->getIJ(P_Si->getIJ(i, 0) + j, 0), 0) + k, 0)] + 1];
1468           }
1469       // Geometric test on scalar product
1470       for (int d = 0; d < 3; d++) // dimension
1471         {
1472           for (int j = 0; j < 2; j++)
1473             n2[j] += std::pow(coord[p[j][1]][d] - coord[p[j][0]][d], 2);
1474           scal += (coord[p[1][1]][d] - coord[p[1][0]][d]) * (coord[p[0][1]][d] - coord[p[0][0]][d]);
1475         }
1476       if (scal * scal > seps * n2[0] * n2[1]) // seps is a sqrt for homogeneity
1477         pt_rem.insert(m_pc[m_pi[i] + 1]);  // point should be removed
1478     }
1479   // Clean connectivity by filtering points to be removed:
1480   DataArrayIdType *old_index = getNodalConnectivityIndex(), *old_conn = getNodalConnectivity();
1481   DAI new_index(DataArrayIdType::New()), new_conn(DataArrayIdType::New());
1482   const mcIdType *old_index_p(old_index->begin()), *old_conn_p(old_conn->begin());
1483   for (mcIdType i = 0; i < getNumberOfCells(); i++)
1484     {
1485       new_index->pushBackSilent(new_conn->getNbOfElems());
1486       for (mcIdType j = old_index_p[i]; j < old_index_p[i + 1]; j++)
1487         {
1488           // Keep point if it is not to be removed, or if is first in connectivity (TODO this last check could be removed?)
1489           if (std::find(pt_rem.begin(), pt_rem.end(), old_conn_p[j]) == pt_rem.end() || j == old_index_p[i])
1490             new_conn->pushBackSilent(old_conn_p[j]);
1491         }
1492     }
1493   new_index->pushBackSilent(new_conn->getNbOfElems());
1494   setConnectivity(new_conn, new_index);
1495 }
1496
1497 /*!
1498  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1499  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1500  * the format of the returned DataArrayIdType instance.
1501  *
1502  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1503  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1504  */
1505 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1506 {
1507   checkConnectivityFullyDefined();
1508   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1509   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1510   std::vector<bool> retS(maxElt,false);
1511   computeNodeIdsAlg(retS);
1512   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1513 }
1514
1515 /*!
1516  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1517  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1518  */
1519 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1520 {
1521   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1522            nbOfCells=getNumberOfCells();
1523   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1524   for(mcIdType i=0;i<nbOfCells;i++)
1525     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1526       if(conn[j]>=0)
1527         {
1528           if(conn[j]<nbOfNodes)
1529             nodeIdsInUse[conn[j]]=true;
1530           else
1531             {
1532               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1533               throw INTERP_KERNEL::Exception(oss.str());
1534             }
1535         }
1536 }
1537
1538 /// @cond INTERNAL
1539
1540 struct MEDCouplingAccVisit
1541 {
1542   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1543   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1544   mcIdType _new_nb_of_nodes;
1545 };
1546
1547 /// @endcond
1548
1549 /*!
1550  * Finds nodes not used in any cell and returns an array giving a new id to every node
1551  * by excluding the unused nodes, for which the array holds -1. The result array is
1552  * a mapping in "Old to New" mode.
1553  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1554  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1555  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1556  *          if the node is unused or a new id else. The caller is to delete this
1557  *          array using decrRef() as it is no more needed.
1558  *  \throw If the coordinates array is not set.
1559  *  \throw If the nodal connectivity of cells is not defined.
1560  *  \throw If the nodal connectivity includes an invalid id.
1561  *
1562  *  \if ENABLE_EXAMPLES
1563  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1564  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1565  *  \endif
1566  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1567  */
1568 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1569 {
1570   nbrOfNodesInUse=-1;
1571   mcIdType nbOfNodes(getNumberOfNodes());
1572   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1573   ret->alloc(nbOfNodes,1);
1574   mcIdType *traducer=ret->getPointer();
1575   std::fill(traducer,traducer+nbOfNodes,-1);
1576   mcIdType nbOfCells=getNumberOfCells();
1577   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1578   const mcIdType *conn=_nodal_connec->getConstPointer();
1579   for(mcIdType i=0;i<nbOfCells;i++)
1580     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1581       if(conn[j]>=0)
1582         {
1583           if(conn[j]<nbOfNodes)
1584             traducer[conn[j]]=1;
1585           else
1586             {
1587               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1588               throw INTERP_KERNEL::Exception(oss.str());
1589             }
1590         }
1591   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1592   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1593   return ret.retn();
1594 }
1595
1596 /*!
1597  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1598  * For each cell in \b this the number of nodes constituting cell is computed.
1599  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1600  * So for pohyhedrons some nodes can be counted several times in the returned result.
1601  *
1602  * \return a newly allocated array
1603  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1604  */
1605 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1606 {
1607   checkConnectivityFullyDefined();
1608   mcIdType nbOfCells=getNumberOfCells();
1609   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1610   ret->alloc(nbOfCells,1);
1611   mcIdType *retPtr=ret->getPointer();
1612   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1613   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1614   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1615     {
1616       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1617         *retPtr=connI[i+1]-connI[i]-1;
1618       else
1619         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1620     }
1621   return ret.retn();
1622 }
1623
1624 /*!
1625  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1626  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1627  *
1628  * \return DataArrayIdType * - new object to be deallocated by the caller.
1629  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1630  */
1631 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1632 {
1633   checkConnectivityFullyDefined();
1634   mcIdType nbOfCells=getNumberOfCells();
1635   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1636   ret->alloc(nbOfCells,1);
1637   mcIdType *retPtr=ret->getPointer();
1638   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1639   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1640   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1641     {
1642       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1643       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1644         *retPtr=ToIdType(s.size());
1645       else
1646         {
1647           s.erase(-1);
1648           *retPtr=ToIdType(s.size());
1649         }
1650     }
1651   return ret.retn();
1652 }
1653
1654 /*!
1655  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1656  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1657  *
1658  * \return a newly allocated array
1659  */
1660 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1661 {
1662   checkConnectivityFullyDefined();
1663   mcIdType nbOfCells=getNumberOfCells();
1664   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1665   ret->alloc(nbOfCells,1);
1666   mcIdType *retPtr=ret->getPointer();
1667   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1668   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1669   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1670     {
1671       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1672       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1673     }
1674   return ret.retn();
1675 }
1676
1677 /*!
1678  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1679  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1680  * array mean that the corresponding old node is no more used.
1681  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1682  *           this->getNumberOfNodes() before call of this method. The caller is to
1683  *           delete this array using decrRef() as it is no more needed.
1684  *  \throw If the coordinates array is not set.
1685  *  \throw If the nodal connectivity of cells is not defined.
1686  *  \throw If the nodal connectivity includes an invalid id.
1687  *  \sa areAllNodesFetched
1688  *
1689  *  \if ENABLE_EXAMPLES
1690  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1691  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1692  *  \endif
1693  */
1694 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1695 {
1696   return MEDCouplingPointSet::zipCoordsTraducer();
1697 }
1698
1699 /*!
1700  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1701  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1702  */
1703 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1704 {
1705   switch(compType)
1706   {
1707     case 0:
1708       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1709     case 1:
1710       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1711     case 2:
1712       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1713     case 3:
1714       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1715     case 7:
1716       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1717   }
1718   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1719 }
1720
1721 /*!
1722  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1723  */
1724 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1725 {
1726   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1727     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1728   return 0;
1729 }
1730
1731 /*!
1732  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1733  */
1734 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1735 {
1736   mcIdType sz=connI[cell1+1]-connI[cell1];
1737   if(sz==connI[cell2+1]-connI[cell2])
1738     {
1739       if(conn[connI[cell1]]==conn[connI[cell2]])
1740         {
1741           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1742           unsigned dim=cm.getDimension();
1743           if(dim!=3)
1744             {
1745               if(dim!=1)
1746                 {
1747                   mcIdType sz1=2*(sz-1);
1748                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1749                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1750                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1751                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1752                   return work!=tmp+sz1?1:0;
1753                 }
1754               else
1755                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1756             }
1757           else
1758             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1759         }
1760     }
1761   return 0;
1762 }
1763
1764 /*!
1765  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1766  */
1767 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1768 {
1769   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1770     {
1771       if(conn[connI[cell1]]==conn[connI[cell2]])
1772         {
1773           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1774           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1775           return s1==s2?1:0;
1776         }
1777     }
1778   return 0;
1779 }
1780
1781 /*!
1782  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1783  */
1784 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1785 {
1786   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1787     {
1788       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1789       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1790       return s1==s2?1:0;
1791     }
1792   return 0;
1793 }
1794
1795 /*!
1796  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1797  */
1798 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1799 {
1800   mcIdType sz=connI[cell1+1]-connI[cell1];
1801   if(sz==connI[cell2+1]-connI[cell2])
1802     {
1803       if(conn[connI[cell1]]==conn[connI[cell2]])
1804         {
1805           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1806           unsigned dim=cm.getDimension();
1807           if(dim!=3)
1808             {
1809               if(dim!=1)
1810                 {
1811                   mcIdType sz1=2*(sz-1);
1812                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1813                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1814                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1815                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1816                   if(work!=tmp+sz1)
1817                     return 1;
1818                   else
1819                     {
1820                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1821                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1822                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1823                         return 2;
1824                       else
1825                         return 0;
1826                     }
1827                 }
1828               else
1829                 {//case of SEG2 and SEG3
1830                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1831                     return 1;
1832                   if(!cm.isQuadratic())
1833                     {
1834                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1835                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1836                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1837                         return 2;
1838                       return 0;
1839                     }
1840                   else
1841                     {
1842                       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])
1843                         return 2;
1844                       return 0;
1845                     }
1846                 }
1847             }
1848           else
1849             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1850         }
1851     }
1852   return 0;
1853 }
1854
1855
1856 /*!
1857  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1858  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1859  * 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.
1860  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1861  * This method is time consuming.
1862  *
1863  * \param [in] compType input specifying the technique used to compare cells each other.
1864  *   - 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.
1865  *   - 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)
1866  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1867  *   - 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
1868  * can be used for users not sensitive to orientation of cell
1869  * \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.
1870  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1871  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1872  *
1873  */
1874 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1875 {
1876   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1877   getReverseNodalConnectivity(revNodal,revNodalI);
1878   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1879 }
1880
1881 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1882                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1883 {
1884   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1885   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1886   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1887   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1888   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1889   std::vector<bool> isFetched(nbOfCells,false);
1890   if(startCellId==0)
1891     {
1892       for(mcIdType i=startCellId;i<nbOfCells;i++)
1893         {
1894           if(!isFetched[i])
1895             {
1896               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));
1897               std::vector<mcIdType> v,v2;
1898               if(connOfNode!=connPtr+connIPtr[i+1])
1899                 {
1900                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1901                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1902                   connOfNode++;
1903                 }
1904               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1905                 if(*connOfNode>=0)
1906                   {
1907                     v=v2;
1908                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1909                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1910                     v2.resize(std::distance(v2.begin(),it));
1911                   }
1912               if(v2.size()>1)
1913                 {
1914                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1915                     {
1916                       mcIdType pos=commonCellsI->back();
1917                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1918                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1919                         isFetched[*it]=true;
1920                     }
1921                 }
1922             }
1923         }
1924     }
1925   else
1926     {
1927       for(mcIdType i=startCellId;i<nbOfCells;i++)
1928         {
1929           if(!isFetched[i])
1930             {
1931               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));
1932               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1933               std::vector<mcIdType> v,v2;
1934               if(connOfNode!=connPtr+connIPtr[i+1])
1935                 {
1936                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1937                   connOfNode++;
1938                 }
1939               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1940                 if(*connOfNode>=0)
1941                   {
1942                     v=v2;
1943                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1944                     v2.resize(std::distance(v2.begin(),it));
1945                   }
1946               // v2 contains now candidates. Problem candidates are sorted using id rank.
1947               if(v2.size()>1)
1948                 {
1949                   if(v2[0]!=i)
1950                   {
1951                     auto it(std::find(v2.begin(),v2.end(),i));
1952                     std::swap(*v2.begin(),*it);
1953                   }
1954                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1955                     {
1956                       mcIdType newPos(commonCells->getNumberOfTuples());
1957                       mcIdType pos(commonCellsI->back());
1958                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1959                       commonCellsI->pushBackSilent(newPos);
1960                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1961                         isFetched[*it]=true;
1962                     }
1963                 }
1964             }
1965         }
1966     }
1967   commonCellsArr=commonCells.retn();
1968   commonCellsIArr=commonCellsI.retn();
1969 }
1970
1971 /*!
1972  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1973  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1974  * than \a this->getNumberOfCells() in the returned array means that there is no
1975  * corresponding cell in \a this mesh.
1976  * It is expected that \a this and \a other meshes share the same node coordinates
1977  * array, if it is not so an exception is thrown.
1978  *  \param [in] other - the mesh to compare with.
1979  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1980  *         valid values [0,1,2], see zipConnectivityTraducer().
1981  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1982  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1983  *         values. The caller is to delete this array using
1984  *         decrRef() as it is no more needed.
1985  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1986  *         mesh.
1987  *
1988  *  \if ENABLE_EXAMPLES
1989  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1990  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1991  *  \endif
1992  *  \sa checkDeepEquivalOnSameNodesWith()
1993  *  \sa checkGeoEquivalWith()
1994  */
1995 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1996 {
1997   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1998   mcIdType nbOfCells=getNumberOfCells();
1999   static const int possibleCompType[]={0,1,2};
2000   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
2001     {
2002       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
2003       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
2004       oss << " !";
2005       throw INTERP_KERNEL::Exception(oss.str());
2006     }
2007   //
2008   if(other->getNumberOfCells()==0)
2009   {
2010     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
2011     return true;
2012   }
2013   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
2014   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
2015   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2016   mcIdType newNbOfCells=-1;
2017   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
2018   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
2019   mcIdType maxPart(p0->getMaxValueInArray());
2020   bool ret(maxPart==newNbOfCells-1);
2021   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
2022   // fill p1 array in case of presence of cells in other not in this
2023   mcIdType *pt(p1->getPointer());
2024   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
2025     pt[i+1] = i+1;
2026   //
2027   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
2028   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
2029   arr = p2.retn();
2030   return ret;
2031 }
2032
2033 /*!
2034  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
2035  * This method tries to determine if \b other is fully included in \b this.
2036  * The main difference is that this method is not expected to throw exception.
2037  * This method has two outputs :
2038  *
2039  * \param other other mesh
2040  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
2041  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
2042  */
2043 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
2044 {
2045   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
2046   DataArrayIdType *commonCells=0,*commonCellsI=0;
2047   mcIdType thisNbCells=getNumberOfCells();
2048   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
2049   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
2050   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
2051   mcIdType otherNbCells=other->getNumberOfCells();
2052   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
2053   arr2->alloc(otherNbCells,1);
2054   arr2->fillWithZero();
2055   mcIdType *arr2Ptr=arr2->getPointer();
2056   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
2057   for(mcIdType i=0;i<nbOfCommon;i++)
2058     {
2059       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
2060       if(start<thisNbCells)
2061         {
2062           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
2063             {
2064               mcIdType sig=commonCellsPtr[j]>0?1:-1;
2065               mcIdType val=std::abs(commonCellsPtr[j])-1;
2066               if(val>=thisNbCells)
2067                 arr2Ptr[val-thisNbCells]=sig*(start+1);
2068             }
2069         }
2070     }
2071   arr2->setName(other->getName());
2072   if(arr2->presenceOfValue(0))
2073     return false;
2074   arr=arr2.retn();
2075   return true;
2076 }
2077
2078 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
2079 {
2080   if(!other)
2081     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
2082   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
2083   if(!otherC)
2084     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
2085   std::vector<const MEDCouplingUMesh *> ms(2);
2086   ms[0]=this;
2087   ms[1]=otherC;
2088   return MergeUMeshesOnSameCoords(ms);
2089 }
2090
2091 /*!
2092  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2093  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2094  * cellIds is not given explicitly but by a range python like.
2095  *
2096  * \param start starting ID
2097  * \param end end ID (excluded)
2098  * \param step step size
2099  * \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.
2100  * \return a newly allocated
2101  *
2102  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2103  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2104  */
2105 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
2106 {
2107   if(getMeshDimension()!=-1)
2108     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2109   else
2110     {
2111       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2112       if(newNbOfCells!=1)
2113         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2114       if(start!=0)
2115         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2116       incrRef();
2117       return const_cast<MEDCouplingUMesh *>(this);
2118     }
2119 }
2120
2121 /*!
2122  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2123  * The result mesh shares or not the node coordinates array with \a this mesh depending
2124  * on \a keepCoords parameter.
2125  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2126  *           to write this mesh to the MED file, its cells must be sorted using
2127  *           sortCellsInMEDFileFrmt().
2128  *  \param [in] begin - an array of cell ids to include to the new mesh.
2129  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2130  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2131  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2132  *         by calling zipCoords().
2133  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2134  *         to delete this mesh using decrRef() as it is no more needed.
2135  *  \throw If the coordinates array is not set.
2136  *  \throw If the nodal connectivity of cells is not defined.
2137  *  \throw If any cell id in the array \a begin is not valid.
2138  *
2139  *  \if ENABLE_EXAMPLES
2140  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2141  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2142  *  \endif
2143  */
2144 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2145 {
2146   if(getMeshDimension()!=-1)
2147     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2148   else
2149     {
2150       if(end-begin!=1)
2151         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2152       if(begin[0]!=0)
2153         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2154       incrRef();
2155       return const_cast<MEDCouplingUMesh *>(this);
2156     }
2157 }
2158
2159 /*!
2160  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2161  *
2162  * 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.
2163  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2164  * The number of cells of \b this will remain the same with this method.
2165  *
2166  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2167  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2168  * \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 ).
2169  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2170  */
2171 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2172 {
2173   checkConnectivityFullyDefined();
2174   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2175   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2176     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2177   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2178     {
2179       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2180       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2181       throw INTERP_KERNEL::Exception(oss.str());
2182     }
2183   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2184   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2185     {
2186       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2187       throw INTERP_KERNEL::Exception(oss.str());
2188     }
2189   mcIdType nbOfCells(getNumberOfCells());
2190   bool easyAssign(true);
2191   const mcIdType *connI(_nodal_connec_index->begin());
2192   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2193   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2194     {
2195       if(*it>=0 && *it<nbOfCells)
2196         {
2197           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2198         }
2199       else
2200         {
2201           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2202           throw INTERP_KERNEL::Exception(oss.str());
2203         }
2204     }
2205   if(easyAssign)
2206     {
2207       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2208       computeTypes();
2209     }
2210   else
2211     {
2212       DataArrayIdType *arrOut=0,*arrIOut=0;
2213       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2214                                                arrOut,arrIOut);
2215       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2216       setConnectivity(arrOut,arrIOut,true);
2217     }
2218 }
2219
2220 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2221 {
2222   checkConnectivityFullyDefined();
2223   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2224   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2225     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2226   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2227     {
2228       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2229       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2230       throw INTERP_KERNEL::Exception(oss.str());
2231     }
2232   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2233   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2234     {
2235       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2236       throw INTERP_KERNEL::Exception(oss.str());
2237     }
2238   mcIdType nbOfCells=getNumberOfCells();
2239   bool easyAssign=true;
2240   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2241   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2242   mcIdType it=start;
2243   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2244     {
2245       if(it>=0 && it<nbOfCells)
2246         {
2247           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2248         }
2249       else
2250         {
2251           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2252           throw INTERP_KERNEL::Exception(oss.str());
2253         }
2254     }
2255   if(easyAssign)
2256     {
2257       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2258       computeTypes();
2259     }
2260   else
2261     {
2262       DataArrayIdType *arrOut=0,*arrIOut=0;
2263       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2264                                                 arrOut,arrIOut);
2265       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2266       setConnectivity(arrOut,arrIOut,true);
2267     }
2268 }
2269
2270
2271 /*!
2272  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2273  * this->getMeshDimension(), that bound some cells of \a this mesh.
2274  * The cells of lower dimension to include to the result mesh are selected basing on
2275  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2276  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2277  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2278  * created mesh shares the node coordinates array with \a this mesh.
2279  *  \param [in] begin - the array of node ids.
2280  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2281  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2282  *         array \a begin are added, else cells whose any node is in the
2283  *         array \a begin are added.
2284  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2285  *         to delete this mesh using decrRef() as it is no more needed.
2286  *  \throw If the coordinates array is not set.
2287  *  \throw If the nodal connectivity of cells is not defined.
2288  *  \throw If any node id in \a begin is not valid.
2289  *
2290  *  \if ENABLE_EXAMPLES
2291  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2292  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2293  *  \endif
2294  */
2295 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2296 {
2297   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2298   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2299   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2300   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2301   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2302 }
2303
2304 /*!
2305  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2306  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2307  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2308  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2309  *         by calling zipCoords().
2310  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2311  *         to delete this mesh using decrRef() as it is no more needed.
2312  *  \throw If the coordinates array is not set.
2313  *  \throw If the nodal connectivity of cells is not defined.
2314  *
2315  *  \if ENABLE_EXAMPLES
2316  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2317  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2318  *  \endif
2319  */
2320 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2321 {
2322   DataArrayIdType *desc=DataArrayIdType::New();
2323   DataArrayIdType *descIndx=DataArrayIdType::New();
2324   DataArrayIdType *revDesc=DataArrayIdType::New();
2325   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2326   //
2327   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2328   revDesc->decrRef();
2329   desc->decrRef();
2330   descIndx->decrRef();
2331   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2332   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2333   std::vector<mcIdType> boundaryCells;
2334   for(mcIdType i=0;i<nbOfCells;i++)
2335     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2336       boundaryCells.push_back(i);
2337   revDescIndx->decrRef();
2338   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2339   return ret;
2340 }
2341
2342 /*!
2343  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2344  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2345  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2346  */
2347 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2348 {
2349   checkFullyDefined();
2350   MCAuto<DataArrayIdType> ret2(DataArrayIdType::New());
2351
2352   if (getNumberOfCells() == 0)
2353     {
2354       ret2->alloc(0,1);
2355       return ret2.retn();
2356     }
2357
2358   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
2359   //
2360   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2361   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2362   //
2363   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2364   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2365   const mcIdType *revDescPtr=revDesc->getConstPointer();
2366   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2367   mcIdType nbOfCells=getNumberOfCells();
2368   std::vector<bool> ret1(nbOfCells,false);
2369   mcIdType sz=0;
2370   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2371     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2372       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2373   //
2374   ret2->alloc(sz,1);
2375   mcIdType *ret2Ptr=ret2->getPointer();
2376   sz=0;
2377   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2378     if(*it)
2379       *ret2Ptr++=sz;
2380   ret2->setName("BoundaryCells");
2381   return ret2.retn();
2382 }
2383
2384 /*!
2385  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2386  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2387  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2388  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2389  *
2390  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2391  * 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
2392  * equals a cell in \b otherDimM1OnSameCoords.
2393  *
2394  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2395  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2396  *
2397  * \param [in] otherDimM1OnSameCoords other mesh
2398  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2399  * \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
2400  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2401  */
2402 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2403 {
2404   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2405     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2406   checkConnectivityFullyDefined();
2407   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2408   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2409     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2410   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2411   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2412   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2413   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2414   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2415   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2416   DataArrayIdType *idsOtherInConsti=0;
2417   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2418   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2419   if(!b)
2420     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2421   std::set<mcIdType> s1;
2422   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2423     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2424   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2425   s1arr_renum1->sort();
2426   cellIdsRk0=s0arr.retn();
2427   //cellIdsRk1=s_renum1.retn();
2428   cellIdsRk1=s1arr_renum1.retn();
2429 }
2430
2431 /*!
2432  * 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
2433  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2434  *
2435  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2436  */
2437 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2438 {
2439   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2440   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2441   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2442   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2443   //
2444   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2445   revDesc=0; desc=0; descIndx=0;
2446   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2447   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2448   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2449 }
2450
2451 /*!
2452  * Finds nodes lying on the boundary of \a this mesh.
2453  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2454  *          nodes. The caller is to delete this array using decrRef() as it is no
2455  *          more needed.
2456  *  \throw If the coordinates array is not set.
2457  *  \throw If the nodal connectivity of cells is node defined.
2458  *
2459  *  \if ENABLE_EXAMPLES
2460  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2461  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2462  *  \endif
2463  */
2464 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2465 {
2466   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2467   return skin->computeFetchedNodeIds();
2468 }
2469
2470 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2471 {
2472   incrRef();
2473   return const_cast<MEDCouplingUMesh *>(this);
2474 }
2475
2476 /*!
2477  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2478  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2479  * This method searches for nodes needed to be duplicated. Those are the nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2480  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords, it will be duplicated.
2481  * 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.
2482  *
2483  * \param [in] crackingMesh a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2484  *             parameter is altered during the call.
2485  * \return node ids which need to be duplicated following the algorithm explained above.
2486  *
2487  */
2488 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& crackingMesh) const
2489 {
2490   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2491   // which mimicks the C++
2492   using DAInt = MCAuto<DataArrayIdType>;
2493   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2494
2495   checkFullyDefined();
2496   crackingMesh.checkFullyDefined();
2497   if(getCoords()!=crackingMesh.getCoords())
2498     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2499   if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2500     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2501
2502   // Clean the M1 group (cracking mesh): the M1 cells which are part of M0 boundary are irrelevant (we can't create a crack on the boundary of M0!)
2503   MCUMesh m0skin = computeSkin();
2504   DataArrayIdType *idsToKeepP;
2505   m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2506   DAInt idsToKeep(idsToKeepP);
2507   DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells());  // discard cells on the skin of M0
2508   MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2509
2510   if (!otherDimM1OnSameCoords->getNumberOfCells())
2511     return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2512
2513   // Checking star-shaped M1 group:
2514   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2515   MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2516   DAInt dsi = rdit0->deltaShiftIndex();
2517   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.
2518   if(idsTmp0->getNumberOfTuples())
2519     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2520   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2521
2522   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2523   // ie nodes belonging to the boundary "cells" (might be points) of M1
2524   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2525   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2526   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2527   // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2528   //    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)
2529   //    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
2530   //    although they are technically on the skin of the cube.
2531   DAInt fNodes = m0skin->computeFetchedNodeIds();
2532   DAInt notDup = 0;
2533   if (getMeshDimension() == 3)
2534     {
2535       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2536       MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2537       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2538       DataArrayIdType * corresp=0;
2539       meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2540       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2541       // In the cube example above, this is a U-shaped polyline.
2542       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2543       corresp->decrRef();
2544       if (validIds->getNumberOfTuples())
2545         {
2546           // 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:
2547           // (the U-shaped polyline described above)
2548           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2549           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2550           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2551           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2552
2553           // Specific logic to handle singular points :
2554           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2555           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2556           //   algorithm would be duplicating too much ...
2557           // 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:
2558           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2559           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2560           dnu1=0;dnu2=0;dnu3=0;
2561           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2562           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2563           if (singPoints->getNumberOfTuples())
2564             {
2565               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2566               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2567               // should not be duplicated
2568               //    1. Extract N D cells touching U-shape line:
2569               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2570               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2571               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2572               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2573               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2574               DataArrayIdType *idsOfM1BNt;
2575               mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2576               DAInt idsOfM1BN(idsOfM1BNt);
2577               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2578               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2579               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2580               for(const auto& v: *idsOfM1BN)
2581                 {
2582                   if (v >= nCellsDesc)    // Keep valid match only
2583                     continue;
2584                   mcIdType idx0 = revDescIBNP[v];
2585                   // Keep the two cells on either side of the face v of M1:
2586                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2587                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2588                 }
2589               //    3. Build complement
2590               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2591               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2592               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2593               DAInt inters = boundNodes->buildIntersection(nod3);
2594               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2595             }
2596           notDup = xtrem->buildSubstraction(fNodes1);
2597         }
2598       else  // if (validIds-> ...)
2599         notDup = xtrem->buildSubstraction(fNodes);
2600     }
2601   else  // if (3D ...)
2602     notDup = xtrem->buildSubstraction(fNodes);
2603
2604   DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2605   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2606   return dupl.retn();
2607 }
2608
2609
2610 /*!
2611  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2612  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2613  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2614  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2615  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2616  *
2617  * \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.
2618  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2619  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2620  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2621  * \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.
2622  *
2623  */
2624 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2625                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2626 {
2627   using DAInt = MCAuto<DataArrayIdType>;
2628   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2629
2630   checkFullyDefined();
2631   otherDimM1OnSameCoords.checkFullyDefined();
2632   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2633     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2634   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2635     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2636
2637   // Degenerated case - no nodes to duplicate
2638   if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2639     {
2640       cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2641       cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2642       return;
2643     }
2644
2645   // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2646   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2647   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2648   mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2649   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2650   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2651   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2652   DataArrayIdType *idsOfM1t;
2653   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2654   DAInt idsOfM1Large(idsOfM1t);
2655   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2656
2657   // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2658   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2659   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2660   DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2661   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2662   DataArrayIdType *neight=0, *neighIt=0;
2663   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2664   DAInt neighL(neight), neighIL(neighIt);
2665
2666   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2667   hitCellsLarge->fillWithValue(0);  // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2668   mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2669
2670   // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2671   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2672   for(const auto& v: *idsOfM1Large)
2673     {
2674       if (v >= nL) continue;   // Keep valid match only - see doc of areCellsIncludedIn()
2675       mcIdType idx0 = revDescILP[v];
2676       // Retrieve the two cells on either side of the face v of M1:
2677       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2678       std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2679       // Handle the spread zones on the two sides of the crack:
2680       for (const auto c: {c1, c2})
2681         {
2682           if (hitCellsLargeP[c]) continue;
2683           // Identify connex zone around this cell - if we find a value already assigned there, use it.
2684           mcIdType dnu;
2685           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2686           std::set<mcIdType> sv;
2687           for (const mcIdType& s: *spreadZone)
2688             if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2689           if (sv.size() > 1)
2690             // Strange: we find in the same spread zone a +1 and -1 !
2691             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2692           // If a valid value was found, use it:
2693           mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2694           // Hopefully this does not conflict with an potential value on the other side:
2695           mcIdType other = toOther[c];
2696           if (hitCellsLargeP[other])
2697             {
2698               if(val && hitCellsLargeP[other] != -val)
2699                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2700               // We do not yet have a value, but other side has one. Use it!
2701               if(!val) val = -hitCellsLargeP[other];
2702             }
2703           // Cover first initialisation:
2704           if (!val) val = 1;
2705           // And finally, fill the current spread zone:
2706           for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2707         }
2708     }
2709
2710   DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2711   DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2712
2713   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2714     {
2715       DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2716       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2717     }
2718   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2719   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2720   //
2721   cellIdsNeededToBeRenum=cellsRet1.retn();
2722   cellIdsNotModified=cellsRet2.retn();
2723 }
2724
2725 /*!
2726  * This method operates a modification of the connectivity and coords in \b this.
2727  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2728  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2729  * 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
2730  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2731  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2732  *
2733  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2734  *
2735  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2736  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2737  */
2738 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2739 {
2740   mcIdType nbOfNodes=getNumberOfNodes();
2741   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2742   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2743 }
2744
2745 /*!
2746  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2747  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2748  *
2749  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2750  *
2751  * \sa renumberNodesInConn
2752  */
2753 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2754 {
2755   checkConnectivityFullyDefined();
2756   mcIdType *conn(getNodalConnectivity()->getPointer());
2757   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2758   mcIdType nbOfCells=getNumberOfCells();
2759   for(mcIdType i=0;i<nbOfCells;i++)
2760     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2761       {
2762         mcIdType& node=conn[iconn];
2763         if(node>=0)//avoid polyhedron separator
2764           {
2765             node+=offset;
2766           }
2767       }
2768   _nodal_connec->declareAsNew();
2769   updateTime();
2770 }
2771
2772 /*!
2773  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2774  *  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
2775  *  of a big mesh.
2776  */
2777 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2778 {
2779   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2780 }
2781
2782 /*!
2783  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2784  *  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
2785  *  of a big mesh.
2786  */
2787 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2788 {
2789   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2790 }
2791
2792 /*!
2793  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2794  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2795  * This method is a generalization of shiftNodeNumbersInConn().
2796  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2797  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2798  *         this->getNumberOfNodes(), in "Old to New" mode.
2799  *         See \ref numbering for more info on renumbering modes.
2800  *  \throw If the nodal connectivity of cells is not defined.
2801  *
2802  *  \if ENABLE_EXAMPLES
2803  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2804  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2805  *  \endif
2806  */
2807 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2808 {
2809   checkConnectivityFullyDefined();
2810   mcIdType *conn=getNodalConnectivity()->getPointer();
2811   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2812   mcIdType nbOfCells=getNumberOfCells();
2813   for(mcIdType i=0;i<nbOfCells;i++)
2814     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2815       {
2816         mcIdType& node=conn[iconn];
2817         if(node>=0)//avoid polyhedron separator
2818           {
2819             node=newNodeNumbersO2N[node];
2820           }
2821       }
2822   _nodal_connec->declareAsNew();
2823   updateTime();
2824 }
2825
2826 /*!
2827  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2828  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2829  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2830  *
2831  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2832  */
2833 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2834 {
2835   checkConnectivityFullyDefined();
2836   mcIdType *conn=getNodalConnectivity()->getPointer();
2837   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2838   mcIdType nbOfCells=getNumberOfCells();
2839   for(mcIdType i=0;i<nbOfCells;i++)
2840     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2841       {
2842         mcIdType& node=conn[iconn];
2843         if(node>=0)//avoid polyhedron separator
2844           {
2845             node+=delta;
2846           }
2847       }
2848   _nodal_connec->declareAsNew();
2849   updateTime();
2850 }
2851
2852 /*!
2853  * This method operates a modification of the connectivity in \b this.
2854  * 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.
2855  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2856  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2857  * 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
2858  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2859  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2860  *
2861  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2862  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2863  *
2864  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2865  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2866  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2867  */
2868 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2869 {
2870   checkConnectivityFullyDefined();
2871   std::map<mcIdType,mcIdType> m;
2872   mcIdType val=offset;
2873   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2874     m[*work]=val;
2875   mcIdType *conn=getNodalConnectivity()->getPointer();
2876   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2877   mcIdType nbOfCells=getNumberOfCells();
2878   for(mcIdType i=0;i<nbOfCells;i++)
2879     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2880       {
2881         mcIdType& node=conn[iconn];
2882         if(node>=0)//avoid polyhedron separator
2883           {
2884             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2885             if(it!=m.end())
2886               node=(*it).second;
2887           }
2888       }
2889   updateTime();
2890 }
2891
2892 /*!
2893  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2894  *
2895  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2896  * After the call of this method the number of cells remains the same as before.
2897  *
2898  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2899  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2900  * be strictly in [0;this->getNumberOfCells()).
2901  *
2902  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2903  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2904  * should be contained in[0;this->getNumberOfCells()).
2905  *
2906  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2907  * \param check whether to check content of old2NewBg
2908  */
2909 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2910 {
2911   checkConnectivityFullyDefined();
2912   mcIdType nbCells=getNumberOfCells();
2913   const mcIdType *array=old2NewBg;
2914   if(check)
2915     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2916   //
2917   const mcIdType *conn=_nodal_connec->getConstPointer();
2918   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2919   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2920   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2921   const mcIdType *n2oPtr=n2o->begin();
2922   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2923   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2924   newConn->copyStringInfoFrom(*_nodal_connec);
2925   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2926   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2927   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2928   //
2929   mcIdType *newC=newConn->getPointer();
2930   mcIdType *newCI=newConnI->getPointer();
2931   mcIdType loc=0;
2932   newCI[0]=loc;
2933   for(mcIdType i=0;i<nbCells;i++)
2934     {
2935       mcIdType pos=n2oPtr[i];
2936       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2937       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2938       loc+=nbOfElts;
2939       newCI[i+1]=loc;
2940     }
2941   //
2942   setConnectivity(newConn,newConnI);
2943   if(check)
2944     free(const_cast<mcIdType *>(array));
2945 }
2946
2947 /*!
2948  * Finds cells whose bounding boxes intersect a given bounding box.
2949  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2950  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2951  *         zMax (if in 3D).
2952  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2953  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2954  *         extent of the bounding box of cell to produce an addition to this bounding box.
2955  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2956  *         cells. The caller is to delete this array using decrRef() as it is no more
2957  *         needed.
2958  *  \throw If the coordinates array is not set.
2959  *  \throw If the nodal connectivity of cells is not defined.
2960  *
2961  *  \if ENABLE_EXAMPLES
2962  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2963  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2964  *  \endif
2965  */
2966 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2967 {
2968   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2969   if(getMeshDimension()==-1)
2970     {
2971       elems->pushBackSilent(0);
2972       return elems.retn();
2973     }
2974   int dim=getSpaceDimension();
2975   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2976   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2977   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2978   const double* coords = getCoords()->getConstPointer();
2979   mcIdType nbOfCells=getNumberOfCells();
2980   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2981     {
2982       for (int i=0; i<dim; i++)
2983         {
2984           elem_bb[i*2]=std::numeric_limits<double>::max();
2985           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2986         }
2987
2988       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2989         {
2990           mcIdType node= conn[inode];
2991           if(node>=0)//avoid polyhedron separator
2992             {
2993               for (int idim=0; idim<dim; idim++)
2994                 {
2995                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2996                     {
2997                       elem_bb[idim*2] = coords[node*dim+idim] ;
2998                     }
2999                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3000                     {
3001                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
3002                     }
3003                 }
3004             }
3005         }
3006       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
3007         elems->pushBackSilent(ielem);
3008     }
3009   return elems.retn();
3010 }
3011
3012 /*!
3013  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
3014  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
3015  * added in 'elems' parameter.
3016  */
3017 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
3018 {
3019   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
3020   if(getMeshDimension()==-1)
3021     {
3022       elems->pushBackSilent(0);
3023       return elems.retn();
3024     }
3025   int dim=getSpaceDimension();
3026   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
3027   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
3028   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
3029   const double* coords = getCoords()->getConstPointer();
3030   mcIdType nbOfCells=getNumberOfCells();
3031   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
3032     {
3033       for (int i=0; i<dim; i++)
3034         {
3035           elem_bb[i*2]=std::numeric_limits<double>::max();
3036           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
3037         }
3038
3039       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3040         {
3041           mcIdType node= conn[inode];
3042           if(node>=0)//avoid polyhedron separator
3043             {
3044               for (int idim=0; idim<dim; idim++)
3045                 {
3046                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
3047                     {
3048                       elem_bb[idim*2] = coords[node*dim+idim] ;
3049                     }
3050                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3051                     {
3052                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
3053                     }
3054                 }
3055             }
3056         }
3057       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3058         elems->pushBackSilent(ielem);
3059     }
3060   return elems.retn();
3061 }
3062
3063 /*!
3064  * Returns a type of a cell by its id.
3065  *  \param [in] cellId - the id of the cell of interest.
3066  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3067  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3068  */
3069 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3070 {
3071   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3072   if(cellId<_nodal_connec_index->getNbOfElems()-1)
3073     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3074   else
3075     {
3076       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3077       throw INTERP_KERNEL::Exception(oss.str());
3078     }
3079 }
3080
3081 /*!
3082  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3083  * This method does not throw exception if geometric type \a type is not in \a this.
3084  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3085  * The coordinates array is not considered here.
3086  *
3087  * \param [in] type the geometric type
3088  * \return cell ids in this having geometric type \a type.
3089  */
3090 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3091 {
3092
3093   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3094   ret->alloc(0,1);
3095   checkConnectivityFullyDefined();
3096   mcIdType nbCells=getNumberOfCells();
3097   int mdim=getMeshDimension();
3098   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3099   if(mdim!=ToIdType(cm.getDimension()))
3100     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3101   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3102   const mcIdType *pt=_nodal_connec->getConstPointer();
3103   for(mcIdType i=0;i<nbCells;i++)
3104     {
3105       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3106         ret->pushBackSilent(i);
3107     }
3108   return ret.retn();
3109 }
3110
3111 /*!
3112  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3113  */
3114 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3115 {
3116   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3117   mcIdType nbOfCells(getNumberOfCells()),ret(0);
3118   for(mcIdType i=0;i<nbOfCells;i++)
3119     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3120       ret++;
3121   return ret;
3122 }
3123
3124 /*!
3125  * Returns the nodal connectivity of a given cell.
3126  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3127  * all returned node ids can be used in getCoordinatesOfNode().
3128  *  \param [in] cellId - an id of the cell of interest.
3129  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3130  *         cleared before the appending.
3131  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3132  */
3133 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3134 {
3135   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3136   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3137     if(*w>=0)
3138       conn.push_back(*w);
3139 }
3140
3141 std::string MEDCouplingUMesh::simpleRepr() const
3142 {
3143   static const char msg0[]="No coordinates specified !";
3144   std::ostringstream ret;
3145   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3146   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3147   int tmpp1,tmpp2;
3148   double tt=getTime(tmpp1,tmpp2);
3149   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3150   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3151   if(_mesh_dim>=-1)
3152     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3153   else
3154     { ret << " Mesh dimension has not been set or is invalid !"; }
3155   if(_coords!=0)
3156     {
3157       const int spaceDim=getSpaceDimension();
3158       ret << spaceDim << "\nInfo attached on space dimension : ";
3159       for(int i=0;i<spaceDim;i++)
3160         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3161       ret << "\n";
3162     }
3163   else
3164     ret << msg0 << "\n";
3165   ret << "Number of nodes : ";
3166   if(_coords!=0)
3167     ret << getNumberOfNodes() << "\n";
3168   else
3169     ret << msg0 << "\n";
3170   ret << "Number of cells : ";
3171   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3172     ret << getNumberOfCells() << "\n";
3173   else
3174     ret << "No connectivity specified !" << "\n";
3175   ret << "Cell types present : ";
3176   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3177     {
3178       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3179       ret << cm.getRepr() << " ";
3180     }
3181   ret << "\n";
3182   return ret.str();
3183 }
3184
3185 std::string MEDCouplingUMesh::advancedRepr() const
3186 {
3187   std::ostringstream ret;
3188   ret << simpleRepr();
3189   ret << "\nCoordinates array : \n___________________\n\n";
3190   if(_coords)
3191     _coords->reprWithoutNameStream(ret);
3192   else
3193     ret << "No array set !\n";
3194   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3195   reprConnectivityOfThisLL(ret);
3196   return ret.str();
3197 }
3198
3199 /*!
3200  * This method returns a C++ code that is a dump of \a this.
3201  * This method will throw if this is not fully defined.
3202  */
3203 std::string MEDCouplingUMesh::cppRepr() const
3204 {
3205   static const char coordsName[]="coords";
3206   static const char connName[]="conn";
3207   static const char connIName[]="connI";
3208   checkFullyDefined();
3209   std::ostringstream ret; ret << "// coordinates" << std::endl;
3210   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3211   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3212   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3213   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3214   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3215   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3216   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3217   return ret.str();
3218 }
3219
3220 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3221 {
3222   std::ostringstream ret;
3223   reprConnectivityOfThisLL(ret);
3224   return ret.str();
3225 }
3226
3227 /*!
3228  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3229  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3230  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3231  * some algos).
3232  *
3233  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3234  * 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
3235  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3236  */
3237 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3238 {
3239   int mdim=getMeshDimension();
3240   if(mdim<0)
3241     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3242   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3243   MCAuto<DataArrayIdType> tmp1,tmp2;
3244   bool needToCpyCT=true;
3245   if(!_nodal_connec)
3246     {
3247       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3248       needToCpyCT=false;
3249     }
3250   else
3251     {
3252       tmp1=_nodal_connec;
3253       tmp1->incrRef();
3254     }
3255   if(!_nodal_connec_index)
3256     {
3257       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3258       needToCpyCT=false;
3259     }
3260   else
3261     {
3262       tmp2=_nodal_connec_index;
3263       tmp2->incrRef();
3264     }
3265   ret->setConnectivity(tmp1,tmp2,false);
3266   if(needToCpyCT)
3267     ret->_types=_types;
3268   if(!_coords)
3269     {
3270       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3271       ret->setCoords(coords);
3272     }
3273   else
3274     ret->setCoords(_coords);
3275   return ret.retn();
3276 }
3277
3278 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3279 {
3280   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3281   const mcIdType *pt=_nodal_connec->getConstPointer();
3282   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3283     return ptI[cellId+1]-ptI[cellId]-1;
3284   else
3285     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3286 }
3287
3288 /*!
3289  * Returns types of cells of the specified part of \a this mesh.
3290  * This method avoids computing sub-mesh explicitly to get its types.
3291  *  \param [in] begin - an array of cell ids of interest.
3292  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3293  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3294  *         describing the cell types.
3295  *  \throw If the coordinates array is not set.
3296  *  \throw If the nodal connectivity of cells is not defined.
3297  *  \sa getAllGeoTypes()
3298  */
3299 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3300 {
3301   checkFullyDefined();
3302   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3303   const mcIdType *conn=_nodal_connec->getConstPointer();
3304   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3305   for(const mcIdType *w=begin;w!=end;w++)
3306     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3307   return ret;
3308 }
3309
3310 /*!
3311  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3312  * Optionally updates
3313  * a set of types of cells constituting \a this mesh.
3314  * This method is for advanced users having prepared their connectivity before. For
3315  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3316  *  \param [in] conn - the nodal connectivity array.
3317  *  \param [in] connIndex - the nodal connectivity index array.
3318  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3319  *         mesh is updated.
3320  */
3321 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3322 {
3323   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3324   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3325   if(isComputingTypes)
3326     computeTypes();
3327   declareAsNew();
3328 }
3329
3330 /*!
3331  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3332  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3333  */
3334 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3335     _nodal_connec(0),_nodal_connec_index(0),
3336     _types(other._types)
3337 {
3338   if(other._nodal_connec)
3339     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3340   if(other._nodal_connec_index)
3341     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3342 }
3343
3344 MEDCouplingUMesh::~MEDCouplingUMesh()
3345 {
3346   if(_nodal_connec)
3347     _nodal_connec->decrRef();
3348   if(_nodal_connec_index)
3349     _nodal_connec_index->decrRef();
3350 }
3351
3352 /*!
3353  * Recomputes a set of cell types of \a this mesh. For more info see
3354  * \ref MEDCouplingUMeshNodalConnectivity.
3355  */
3356 void MEDCouplingUMesh::computeTypes()
3357 {
3358   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3359 }
3360
3361
3362 /*!
3363  * Returns a number of cells constituting \a this mesh.
3364  *  \return mcIdType - the number of cells in \a this mesh.
3365  *  \throw If the nodal connectivity of cells is not defined.
3366  */
3367 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3368 {
3369   if(_nodal_connec_index)
3370     return _nodal_connec_index->getNumberOfTuples()-1;
3371   else
3372     if(_mesh_dim==-1)
3373       return 1;
3374     else
3375       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3376 }
3377
3378 /*!
3379  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3380  * mesh. For more info see \ref meshes.
3381  *  \return int - the dimension of \a this mesh.
3382  *  \throw If the mesh dimension is not defined using setMeshDimension().
3383  */
3384 int MEDCouplingUMesh::getMeshDimension() const
3385 {
3386   if(_mesh_dim<-1)
3387     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3388   return _mesh_dim;
3389 }
3390
3391 /*!
3392  * Returns a length of the nodal connectivity array.
3393  * This method is for test reason. Normally the integer returned is not useable by
3394  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3395  *  \return mcIdType - the length of the nodal connectivity array.
3396  */
3397 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3398 {
3399   return _nodal_connec->getNbOfElems();
3400 }
3401
3402 /*!
3403  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3404  */
3405 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3406 {
3407   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3408   tinyInfo.push_back(ToIdType(getMeshDimension()));
3409   tinyInfo.push_back(getNumberOfCells());
3410   if(_nodal_connec)
3411     tinyInfo.push_back(getNodalConnectivityArrayLen());
3412   else
3413     tinyInfo.push_back(-1);
3414 }
3415
3416 /*!
3417  * First step of unserialization process.
3418  */
3419 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3420 {
3421   return tinyInfo[6]<=0;
3422 }
3423
3424 /*!
3425  * Second step of serialization process.
3426  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3427  * \param a1 DataArrayDouble
3428  * \param a2 DataArrayDouble
3429  * \param littleStrings string vector
3430  */
3431 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3432 {
3433   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3434   if(tinyInfo[5]!=-1)
3435     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3436 }
3437
3438 /*!
3439  * Third and final step of serialization process.
3440  */
3441 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3442 {
3443   MEDCouplingPointSet::serialize(a1,a2);
3444   if(getMeshDimension()>-1)
3445     {
3446       a1=DataArrayIdType::New();
3447       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3448       mcIdType *ptA1=a1->getPointer();
3449       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3450       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3451       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3452       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3453     }
3454   else
3455     a1=0;
3456 }
3457
3458 /*!
3459  * Second and final unserialization process.
3460  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3461  */
3462 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3463 {
3464   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3465   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3466   if(tinyInfo[7]!=-1)
3467     {
3468       // Connectivity
3469       const mcIdType *recvBuffer=a1->getConstPointer();
3470       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3471       myConnecIndex->alloc(tinyInfo[6]+1,1);
3472       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3473       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3474       myConnec->alloc(tinyInfo[7],1);
3475       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3476       setConnectivity(myConnec, myConnecIndex);
3477     }
3478 }
3479
3480
3481
3482 /*!
3483  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3484  * mesh.<br>
3485  * For 1D cells, the returned field contains lengths.<br>
3486  * For 2D cells, the returned field contains areas.<br>
3487  * For 3D cells, the returned field contains volumes.
3488  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3489  *         orientation, i.e. the volume is always positive.
3490  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3491  *         and one time . The caller is to delete this field using decrRef() as it is no
3492  *         more needed.
3493  */
3494 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3495 {
3496   std::string name="MeasureOfMesh_";
3497   name+=getName();
3498   mcIdType nbelem=getNumberOfCells();
3499   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3500   field->setName(name);
3501   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3502   array->alloc(nbelem,1);
3503   double *area_vol=array->getPointer();
3504   field->setArray(array) ; array=0;
3505   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3506   field->synchronizeTimeWithMesh();
3507   if(getMeshDimension()!=-1)
3508     {
3509       mcIdType ipt;
3510       INTERP_KERNEL::NormalizedCellType type;
3511       int dim_space=getSpaceDimension();
3512       const double *coords=getCoords()->getConstPointer();
3513       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3514       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3515       for(mcIdType iel=0;iel<nbelem;iel++)
3516         {
3517           ipt=connec_index[iel];
3518           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3519           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);
3520         }
3521       if(isAbs)
3522         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3523     }
3524   else
3525     {
3526       area_vol[0]=std::numeric_limits<double>::max();
3527     }
3528   return field.retn();
3529 }
3530
3531 /*!
3532  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3533  * mesh.<br>
3534  * For 1D cells, the returned array contains lengths.<br>
3535  * For 2D cells, the returned array contains areas.<br>
3536  * For 3D cells, the returned array contains volumes.
3537  * This method avoids building explicitly a part of \a this mesh to perform the work.
3538  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3539  *         orientation, i.e. the volume is always positive.
3540  *  \param [in] begin - an array of cell ids of interest.
3541  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3542  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3543  *          delete this array using decrRef() as it is no more needed.
3544  *
3545  *  \if ENABLE_EXAMPLES
3546  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3547  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3548  *  \endif
3549  *  \sa getMeasureField()
3550  */
3551 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3552 {
3553   std::string name="PartMeasureOfMesh_";
3554   name+=getName();
3555   std::size_t nbelem=std::distance(begin,end);
3556   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3557   array->setName(name);
3558   array->alloc(nbelem,1);
3559   double *area_vol=array->getPointer();
3560   if(getMeshDimension()!=-1)
3561     {
3562       mcIdType ipt;
3563       INTERP_KERNEL::NormalizedCellType type;
3564       int dim_space=getSpaceDimension();
3565       const double *coords=getCoords()->getConstPointer();
3566       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3567       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3568       for(const mcIdType *iel=begin;iel!=end;iel++)
3569         {
3570           ipt=connec_index[*iel];
3571           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3572           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3573         }
3574       if(isAbs)
3575         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3576     }
3577   else
3578     {
3579       area_vol[0]=std::numeric_limits<double>::max();
3580     }
3581   return array.retn();
3582 }
3583
3584 /*!
3585  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3586  * \a this one. The returned field contains the dual cell volume for each corresponding
3587  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3588  *  the dual mesh in P1 sens of \a this.<br>
3589  * For 1D cells, the returned field contains lengths.<br>
3590  * For 2D cells, the returned field contains areas.<br>
3591  * For 3D cells, the returned field contains volumes.
3592  * This method is useful to check "P1*" conservative interpolators.
3593  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3594  *         orientation, i.e. the volume is always positive.
3595  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3596  *          nodes and one time. The caller is to delete this array using decrRef() as
3597  *          it is no more needed.
3598  */
3599 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3600 {
3601   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3602   std::string name="MeasureOnNodeOfMesh_";
3603   name+=getName();
3604   mcIdType nbNodes=getNumberOfNodes();
3605   MCAuto<DataArrayDouble> nnpc;
3606   {
3607     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3608     nnpc=tmp2->convertToDblArr();
3609   }
3610   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3611   const double *nnpcPtr(nnpc->begin());
3612   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3613   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3614   array->alloc(nbNodes,1);
3615   double *valsToFill=array->getPointer();
3616   std::fill(valsToFill,valsToFill+nbNodes,0.);
3617   const double *values=tmp->getArray()->getConstPointer();
3618   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3619   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3620   getReverseNodalConnectivity(da,daInd);
3621   const mcIdType *daPtr=da->getConstPointer();
3622   const mcIdType *daIPtr=daInd->getConstPointer();
3623   for(mcIdType i=0;i<nbNodes;i++)
3624     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3625       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3626   ret->setMesh(this);
3627   ret->setArray(array);
3628   return ret.retn();
3629 }
3630
3631 /*!
3632  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3633  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3634  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3635  * and are normalized.
3636  * <br> \a this can be either
3637  * - a  2D mesh in 2D or 3D space or
3638  * - an 1D mesh in 2D space.
3639  *
3640  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3641  *          cells and one time. The caller is to delete this field using decrRef() as
3642  *          it is no more needed.
3643  *  \throw If the nodal connectivity of cells is not defined.
3644  *  \throw If the coordinates array is not set.
3645  *  \throw If the mesh dimension is not set.
3646  *  \throw If the mesh and space dimension is not as specified above.
3647  */
3648 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3649 {
3650   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3651     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3652   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3653   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3654   mcIdType nbOfCells=getNumberOfCells();
3655   int nbComp=getMeshDimension()+1;
3656   array->alloc(nbOfCells,nbComp);
3657   double *vals=array->getPointer();
3658   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3659   const mcIdType *conn=_nodal_connec->getConstPointer();
3660   const double *coords=_coords->getConstPointer();
3661   if(getMeshDimension()==2)
3662     {
3663       if(getSpaceDimension()==3)
3664         {
3665           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3666           const double *locPtr=loc->getConstPointer();
3667           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3668             {
3669               mcIdType offset=connI[i];
3670               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3671               double n=INTERP_KERNEL::norm<3>(vals);
3672               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3673             }
3674         }
3675       else
3676         {
3677           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3678           const double *isAbsPtr=isAbs->getArray()->begin();
3679           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3680             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3681         }
3682     }
3683   else//meshdimension==1
3684     {
3685       double tmp[2];
3686       for(mcIdType i=0;i<nbOfCells;i++)
3687         {
3688           mcIdType offset=connI[i];
3689           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3690           double n=INTERP_KERNEL::norm<2>(tmp);
3691           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3692           *vals++=-tmp[1];
3693           *vals++=tmp[0];
3694         }
3695     }
3696   ret->setArray(array);
3697   ret->setMesh(this);
3698   ret->synchronizeTimeWithSupport();
3699   return ret.retn();
3700 }
3701
3702 /*!
3703  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3704  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3705  * and are normalized.
3706  * <br> \a this can be either
3707  * - a  2D mesh in 2D or 3D space or
3708  * - an 1D mesh in 2D space.
3709  *
3710  * This method avoids building explicitly a part of \a this mesh to perform the work.
3711  *  \param [in] begin - an array of cell ids of interest.
3712  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3713  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3714  *          cells and one time. The caller is to delete this field using decrRef() as
3715  *          it is no more needed.
3716  *  \throw If the nodal connectivity of cells is not defined.
3717  *  \throw If the coordinates array is not set.
3718  *  \throw If the mesh dimension is not set.
3719  *  \throw If the mesh and space dimension is not as specified above.
3720  *  \sa buildOrthogonalField()
3721  *
3722  *  \if ENABLE_EXAMPLES
3723  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3724  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3725  *  \endif
3726  */
3727 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3728 {
3729   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3730     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3731   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3732   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3733   std::size_t nbelems=std::distance(begin,end);
3734   int nbComp=getMeshDimension()+1;
3735   array->alloc(nbelems,nbComp);
3736   double *vals=array->getPointer();
3737   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3738   const mcIdType *conn=_nodal_connec->getConstPointer();
3739   const double *coords=_coords->getConstPointer();
3740   if(getMeshDimension()==2)
3741     {
3742       if(getSpaceDimension()==3)
3743         {
3744           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3745           const double *locPtr=loc->getConstPointer();
3746           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3747             {
3748               mcIdType offset=connI[*i];
3749               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3750               double n=INTERP_KERNEL::norm<3>(vals);
3751               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3752             }
3753         }
3754       else
3755         {
3756           for(std::size_t i=0;i<nbelems;i++)
3757             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3758         }
3759     }
3760   else//meshdimension==1
3761     {
3762       double tmp[2];
3763       for(const mcIdType *i=begin;i!=end;i++)
3764         {
3765           mcIdType offset=connI[*i];
3766           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3767           double n=INTERP_KERNEL::norm<2>(tmp);
3768           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3769           *vals++=-tmp[1];
3770           *vals++=tmp[0];
3771         }
3772     }
3773   ret->setArray(array);
3774   ret->setMesh(this);
3775   ret->synchronizeTimeWithSupport();
3776   return ret.retn();
3777 }
3778
3779 /*!
3780  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3781  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3782  * and are \b not normalized.
3783  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3784  *          cells and one time. The caller is to delete this field using decrRef() as
3785  *          it is no more needed.
3786  *  \throw If the nodal connectivity of cells is not defined.
3787  *  \throw If the coordinates array is not set.
3788  *  \throw If \a this->getMeshDimension() != 1.
3789  *  \throw If \a this mesh includes cells of type other than SEG2.
3790  */
3791 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3792 {
3793   if(getMeshDimension()!=1)
3794     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3795   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3796     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3797   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3798   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3799   mcIdType nbOfCells=getNumberOfCells();
3800   int spaceDim=getSpaceDimension();
3801   array->alloc(nbOfCells,spaceDim);
3802   double *pt=array->getPointer();
3803   const double *coo=getCoords()->getConstPointer();
3804   std::vector<mcIdType> conn;
3805   conn.reserve(2);
3806   for(mcIdType i=0;i<nbOfCells;i++)
3807     {
3808       conn.resize(0);
3809       getNodeIdsOfCell(i,conn);
3810       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3811     }
3812   ret->setArray(array);
3813   ret->setMesh(this);
3814   ret->synchronizeTimeWithSupport();
3815   return ret.retn();
3816 }
3817
3818 /*!
3819  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3820  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3821  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3822  * from. If a result face is shared by two 3D cells, then the face in included twice in
3823  * the result mesh.
3824  *  \param [in] origin - 3 components of a point defining location of the plane.
3825  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3826  *         must be greater than 1e-6.
3827  *  \param [in] eps - half-thickness of the plane.
3828  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3829  *         producing correspondent 2D cells. The caller is to delete this array
3830  *         using decrRef() as it is no more needed.
3831  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3832  *         not share the node coordinates array with \a this mesh. The caller is to
3833  *         delete this mesh using decrRef() as it is no more needed.
3834  *  \throw If the coordinates array is not set.
3835  *  \throw If the nodal connectivity of cells is not defined.
3836  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3837  *  \throw If magnitude of \a vec is less than 1e-6.
3838  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3839  *  \throw If \a this includes quadratic cells.
3840  */
3841 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3842 {
3843   checkFullyDefined();
3844   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3845     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3846   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3847   if(candidates->empty())
3848     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3849   std::vector<mcIdType> nodes;
3850   DataArrayIdType *cellIds1D=0;
3851   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3852   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3853   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3854   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3855   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3856   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3857   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3858   revDesc2=0; revDescIndx2=0;
3859   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3860   revDesc1=0; revDescIndx1=0;
3861   //Marking all 1D cells that contained at least one node located on the plane
3862   //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3863   //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3864   //due to accuracy errors when the needed nodes already exist)
3865   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3866   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3867   //
3868   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3869   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3870     cut3DCurve[*it]=-1;
3871   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3872   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3873   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3874                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3875                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3876   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3877   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3878   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3879   if(cellIds2->empty())
3880     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3881   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3882   ret->setCoords(mDesc1->getCoords());
3883   ret->setConnectivity(conn,connI,true);
3884   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3885   return ret.retn();
3886 }
3887
3888 /*!
3889  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3890 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
3891 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3892 the result mesh.
3893  *  \param [in] origin - 3 components of a point defining location of the plane.
3894  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3895  *         must be greater than 1e-6.
3896  *  \param [in] eps - half-thickness of the plane.
3897  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3898  *         producing correspondent segments. The caller is to delete this array
3899  *         using decrRef() as it is no more needed.
3900  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3901  *         mesh in 3D space. This mesh does not share the node coordinates array with
3902  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3903  *         no more needed.
3904  *  \throw If the coordinates array is not set.
3905  *  \throw If the nodal connectivity of cells is not defined.
3906  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3907  *  \throw If magnitude of \a vec is less than 1e-6.
3908  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3909  *  \throw If \a this includes quadratic cells.
3910  */
3911 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3912 {
3913   checkFullyDefined();
3914   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3915     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3916   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3917   if(candidates->empty())
3918     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3919   std::vector<mcIdType> nodes;
3920   DataArrayIdType *cellIds1D(0);
3921   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3922   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3923   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3924   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3925   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3926   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3927   //
3928   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3929   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3930     cut3DCurve[*it]=-1;
3931   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3932   mcIdType ncellsSub=subMesh->getNumberOfCells();
3933   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3934   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3935                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3936                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3937   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3938   conn->alloc(0,1);
3939   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3940   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3941   for(mcIdType i=0;i<ncellsSub;i++)
3942     {
3943       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3944         {
3945           if(cut3DSurf[i].first!=-2)
3946             {
3947               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3948               connI->pushBackSilent(conn->getNumberOfTuples());
3949               cellIds2->pushBackSilent(i);
3950             }
3951           else
3952             {
3953               mcIdType cellId3DSurf=cut3DSurf[i].second;
3954               mcIdType offset=nodalI[cellId3DSurf]+1;
3955               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3956               for(mcIdType j=0;j<nbOfEdges;j++)
3957                 {
3958                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3959                   connI->pushBackSilent(conn->getNumberOfTuples());
3960                   cellIds2->pushBackSilent(cellId3DSurf);
3961                 }
3962             }
3963         }
3964     }
3965   if(cellIds2->empty())
3966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3967   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3968   ret->setCoords(mDesc1->getCoords());
3969   ret->setConnectivity(conn,connI,true);
3970   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3971   return ret.retn();
3972 }
3973
3974 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3975 {
3976   checkFullyDefined();
3977   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3978     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3979   if(getNumberOfCells()!=1)
3980     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3981   //
3982   std::vector<mcIdType> nodes;
3983   findNodesOnPlane(origin,vec,eps,nodes);
3984   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());
3985   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3986   revDesc2=0; revDescIndx2=0;
3987   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3988   revDesc1=0; revDescIndx1=0;
3989   DataArrayIdType *cellIds1D(0);
3990   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3991   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3992   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3993   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3994     cut3DCurve[*it]=-1;
3995   bool sameNbNodes;
3996   {
3997     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3998     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3999     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
4000   }
4001   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
4002   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
4003                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
4004                               desc1->begin(),descIndx1->begin(),cut3DSurf);
4005   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
4006   connI->pushBackSilent(0); conn->alloc(0,1);
4007   {
4008     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
4009     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
4010     if(cellIds2->empty())
4011       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
4012   }
4013   std::vector<std::vector<mcIdType> > res;
4014   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
4015   std::size_t sz(res.size());
4016   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
4017     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
4018   for(std::size_t i=0;i<sz;i++)
4019     {
4020       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
4021       conn->insertAtTheEnd(res[i].begin(),res[i].end());
4022       connI->pushBackSilent(conn->getNumberOfTuples());
4023     }
4024   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4025   ret->setCoords(mDesc1->getCoords());
4026   ret->setConnectivity(conn,connI,true);
4027   mcIdType nbCellsRet(ret->getNumberOfCells());
4028   //
4029   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4030   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4031   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4032   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4033   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4034   MCAuto<DataArrayDouble> occm;
4035   {
4036     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4037     occm=DataArrayDouble::Substract(ccm,pt);
4038   }
4039   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4040   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);
4041   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4042   //
4043   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4044   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4045   ret2->setCoords(mDesc1->getCoords());
4046   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4047   conn2I->pushBackSilent(0); conn2->alloc(0,1);
4048   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4049   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4050   if(dott->getIJ(0,0)>0)
4051     {
4052       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4053       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4054     }
4055   else
4056     {
4057       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4058       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4059     }
4060   for(mcIdType i=1;i<nbCellsRet;i++)
4061     {
4062       if(dott2->getIJ(i,0)<0)
4063         {
4064           if(ciPtr[i+1]-ciPtr[i]>=4)
4065             {
4066               cell0.push_back(-1);
4067               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4068             }
4069         }
4070       else
4071         {
4072           if(ciPtr[i+1]-ciPtr[i]>=4)
4073             {
4074               cell1.push_back(-1);
4075               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4076             }
4077         }
4078     }
4079   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4080   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4081   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4082   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4083   ret2->setConnectivity(conn2,conn2I,true);
4084   ret2->checkConsistencyLight();
4085   ret2->orientCorrectlyPolyhedrons();
4086   return ret2;
4087 }
4088
4089 /*!
4090  * Finds cells whose bounding boxes intersect a given plane.
4091  *  \param [in] origin - 3 components of a point defining location of the plane.
4092  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4093  *         must be greater than 1e-6.
4094  *  \param [in] eps - half-thickness of the plane.
4095  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4096  *         cells. The caller is to delete this array using decrRef() as it is no more
4097  *         needed.
4098  *  \throw If the coordinates array is not set.
4099  *  \throw If the nodal connectivity of cells is not defined.
4100  *  \throw If \a this->getSpaceDimension() != 3.
4101  *  \throw If magnitude of \a vec is less than 1e-6.
4102  *  \sa buildSlice3D()
4103  */
4104 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4105 {
4106   checkFullyDefined();
4107   if(getSpaceDimension()!=3)
4108     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4109   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4110   if(normm<1e-6)
4111     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4112   double vec2[3];
4113   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4114   double angle=acos(vec[2]/normm);
4115   MCAuto<DataArrayIdType> cellIds;
4116   double bbox[6];
4117   if(angle>eps)
4118     {
4119       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4120       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4121       if(normm2/normm>1e-6)
4122         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4123       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4124       mw->setCoords(coo);
4125       mw->getBoundingBox(bbox);
4126       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4127       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4128     }
4129   else
4130     {
4131       getBoundingBox(bbox);
4132       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4133       cellIds=getCellsInBoundingBox(bbox,eps);
4134     }
4135   return cellIds.retn();
4136 }
4137
4138 /*!
4139  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4140  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4141  * No consideration of coordinate is done by this method.
4142  * 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)
4143  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4144  */
4145 bool MEDCouplingUMesh::isContiguous1D() const
4146 {
4147   if(getMeshDimension()!=1)
4148     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4149   mcIdType nbCells=getNumberOfCells();
4150   if(nbCells<1)
4151     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4152   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4153   mcIdType ref=conn[connI[0]+2];
4154   for(mcIdType i=1;i<nbCells;i++)
4155     {
4156       if(conn[connI[i]+1]!=ref)
4157         return false;
4158       ref=conn[connI[i]+2];
4159     }
4160   return true;
4161 }
4162
4163 /*!
4164  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4165  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4166  * \param pt reference point of the line
4167  * \param v normalized director vector of the line
4168  * \param eps max precision before throwing an exception
4169  * \param res output of size this->getNumberOfCells
4170  */
4171 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4172 {
4173   if(getMeshDimension()!=1)
4174     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4175   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4176     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4177   if(getSpaceDimension()!=3)
4178     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4179   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4180   const double *fPtr=f->getArray()->getConstPointer();
4181   double tmp[3];
4182   for(mcIdType i=0;i<getNumberOfCells();i++)
4183     {
4184       const double *tmp1=fPtr+3*i;
4185       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4186       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4187       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4188       double n1=INTERP_KERNEL::norm<3>(tmp);
4189       n1/=INTERP_KERNEL::norm<3>(tmp1);
4190       if(n1>eps)
4191         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4192     }
4193   const double *coo=getCoords()->getConstPointer();
4194   for(mcIdType i=0;i<getNumberOfNodes();i++)
4195     {
4196       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4197       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4198       res[i]=std::accumulate(tmp,tmp+3,0.);
4199     }
4200 }
4201
4202 /*!
4203  * 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.
4204  * \a this is expected to be a mesh so that its space dimension is equal to its
4205  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4206  * 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).
4207  *
4208  * 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
4209  * 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).
4210  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4211  *
4212  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4213  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4214  *
4215  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4216  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4217  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4218  * \return the positive value of the distance.
4219  * \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
4220  * dimension - 1.
4221  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4222  */
4223 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4224 {
4225   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4226   if(meshDim!=spaceDim-1)
4227     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4228   if(meshDim!=2 && meshDim!=1)
4229     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4230   checkFullyDefined();
4231   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4232     { 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()); }
4233   DataArrayIdType *ret1=0;
4234   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4235   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4236   MCAuto<DataArrayIdType> ret1Safe(ret1);
4237   cellId=*ret1Safe->begin();
4238   return *ret0->begin();
4239 }
4240
4241 /*!
4242  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4243  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4244  * 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
4245  * 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).
4246  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4247  *
4248  * \a this is expected to be a mesh so that its space dimension is equal to its
4249  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4250  * 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).
4251  *
4252  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4253  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4254  *
4255  * \param [in] pts the list of points in which each tuple represents a point
4256  * \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.
4257  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4258  * \throw if number of components of \a pts is not equal to the space dimension.
4259  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4260  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4261  */
4262 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4263 {
4264   if(!pts)
4265     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4266   pts->checkAllocated();
4267   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4268   if(meshDim!=spaceDim-1)
4269     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4270   if(meshDim!=2 && meshDim!=1)
4271     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4272   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4273     {
4274       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4275       throw INTERP_KERNEL::Exception(oss.str());
4276     }
4277   checkFullyDefined();
4278   mcIdType nbCells=getNumberOfCells();
4279   if(nbCells==0)
4280     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4281   mcIdType nbOfPts=pts->getNumberOfTuples();
4282   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4283   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4284   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4285   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4286   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4287   const double *bbox(bboxArr->begin());
4288   switch(spaceDim)
4289   {
4290     case 3:
4291       {
4292         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4293         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4294           {
4295             double x=std::numeric_limits<double>::max();
4296             std::vector<mcIdType> elems;
4297             myTree.getMinDistanceOfMax(ptsPtr,x);
4298             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4299             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4300           }
4301         break;
4302       }
4303     case 2:
4304       {
4305         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4306         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4307           {
4308             double x=std::numeric_limits<double>::max();
4309             std::vector<mcIdType> elems;
4310             myTree.getMinDistanceOfMax(ptsPtr,x);
4311             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4312             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4313           }
4314         break;
4315       }
4316     default:
4317       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4318   }
4319   cellIds=ret1.retn();
4320   return ret0.retn();
4321 }
4322
4323 /// @cond INTERNAL
4324
4325 /// @endcond
4326
4327 /*!
4328  * Finds cells in contact with a ball (i.e. a point with precision).
4329  * 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.
4330  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4331  *
4332  * \warning This method is suitable if the caller intends to evaluate only one
4333  *          point, for more points getCellsContainingPoints() is recommended as it is
4334  *          faster.
4335  *  \param [in] pos - array of coordinates of the ball central point.
4336  *  \param [in] eps - ball radius.
4337  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4338  *         if there are no such cells.
4339  *  \throw If the coordinates array is not set.
4340  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4341  */
4342 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4343 {
4344   std::vector<mcIdType> elts;
4345   getCellsContainingPoint(pos,eps,elts);
4346   if(elts.empty())
4347     return -1;
4348   return elts.front();
4349 }
4350
4351 /*!
4352  * Finds cells in contact with a ball (i.e. a point with precision).
4353  * 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.
4354  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4355  * \warning This method is suitable if the caller intends to evaluate only one
4356  *          point, for more points getCellsContainingPoints() is recommended as it is
4357  *          faster.
4358  *  \param [in] pos - array of coordinates of the ball central point.
4359  *  \param [in] eps - ball radius (i.e. the precision) relative to max dimension along X, Y or Z of the the considered cell bounding box.
4360  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4361  *         before inserting ids.
4362  *  \throw If the coordinates array is not set.
4363  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4364  *
4365  *  \if ENABLE_EXAMPLES
4366  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4367  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4368  *  \endif
4369  */
4370 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4371 {
4372   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4373   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4374   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4375 }
4376
4377 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4378                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4379                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4380 {
4381   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4382   if(spaceDim==3)
4383     {
4384       if(mDim==3)
4385         {
4386           const double *coords=_coords->getConstPointer();
4387           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4388         }
4389       else
4390         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4391     }
4392   else if(spaceDim==2)
4393     {
4394       if(mDim==2)
4395         {
4396           const double *coords=_coords->getConstPointer();
4397           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4398         }
4399       else
4400         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4401     }
4402   else if(spaceDim==1)
4403     {
4404       if(mDim==1)
4405         {
4406           const double *coords=_coords->getConstPointer();
4407           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4408         }
4409       else
4410         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4411     }
4412   else
4413     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4414 }
4415
4416 /*!
4417  * Finds cells in contact with several balls (i.e. points with precision).
4418  * This method is an extension of getCellContainingPoint() and
4419  * getCellsContainingPoint() for the case of multiple points.
4420  * 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.
4421  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4422  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4423  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4424  *         this->getSpaceDimension() * \a nbOfPoints
4425  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4426  *  \param [in] eps - ball radius (i.e. the precision) relative to max dimension along X, Y or Z of the the considered cell bounding box.
4427  *  \param [out] elts - vector returning ids of found cells.
4428  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4429  *         dividing cell ids in \a elts into groups each referring to one
4430  *         point. Its every element (except the last one) is an index pointing to the
4431  *         first id of a group of cells. For example cells in contact with the *i*-th
4432  *         point are described by following range of indices:
4433  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4434  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4435  *         Number of cells in contact with the *i*-th point is
4436  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4437  *  \throw If the coordinates array is not set.
4438  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4439  *
4440  *  \if ENABLE_EXAMPLES
4441  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4442  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4443  *  \endif
4444  */
4445 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4446                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4447 {
4448   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4449   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4450 }
4451
4452 /*!
4453  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4454  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4455  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4456  * 
4457  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4458  */
4459 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4460 {
4461   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4462   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4463 }
4464
4465 /*!
4466  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4467  * least two its edges intersect each other anywhere except their extremities. An
4468  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4469  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4470  *         cleared before filling in.
4471  *  \param [in] eps - precision.
4472  *  \throw If \a this->getMeshDimension() != 2.
4473  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4474  */
4475 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4476 {
4477   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4478   if(getMeshDimension()!=2)
4479     throw INTERP_KERNEL::Exception(msg);
4480   int spaceDim=getSpaceDimension();
4481   if(spaceDim!=2 && spaceDim!=3)
4482     throw INTERP_KERNEL::Exception(msg);
4483   const mcIdType *conn=_nodal_connec->getConstPointer();
4484   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4485   mcIdType nbOfCells=getNumberOfCells();
4486   std::vector<double> cell2DinS2;
4487   for(mcIdType i=0;i<nbOfCells;i++)
4488     {
4489       mcIdType offset=connI[i];
4490       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4491       if(nbOfNodesForCell<=3)
4492         continue;
4493       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4494       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4495       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4496         cells.push_back(i);
4497       cell2DinS2.clear();
4498     }
4499 }
4500
4501 /*!
4502  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4503  *
4504  * 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.
4505  * 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.
4506  *
4507  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4508  * This convex envelop is computed using Jarvis march algorithm.
4509  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4510  * 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)
4511  * 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.
4512  *
4513  * \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.
4514  * \sa MEDCouplingUMesh::colinearize2D
4515  */
4516 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4517 {
4518   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4519     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4520   checkFullyDefined();
4521   const double *coords=getCoords()->getConstPointer();
4522   mcIdType nbOfCells=getNumberOfCells();
4523   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4524   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4525   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4526   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4527   *workIndexOut=0;
4528   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4529   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4530   std::set<INTERP_KERNEL::NormalizedCellType> types;
4531   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4532   isChanged->alloc(0,1);
4533   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4534     {
4535       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4536       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4537         isChanged->pushBackSilent(i);
4538       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4539       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4540     }
4541   if(isChanged->empty())
4542     return 0;
4543   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4544   _types=types;
4545   return isChanged.retn();
4546 }
4547
4548 /*!
4549  * This method is \b NOT const because it can modify \a this.
4550  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4551  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4552  * \param policy specifies the type of extrusion chosen:
4553  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4554  *   will be repeated to build each level
4555  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4556  *   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
4557  *   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
4558  *   arc.
4559  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4560  */
4561 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4562 {
4563   checkFullyDefined();
4564   mesh1D->checkFullyDefined();
4565   if(!mesh1D->isContiguous1D())
4566     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4567   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4568     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4569   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4570     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4571   if(mesh1D->getMeshDimension()!=1)
4572     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4573   bool isQuad=false;
4574   if(isPresenceOfQuadratic())
4575     {
4576       if(mesh1D->isFullyQuadratic())
4577         isQuad=true;
4578       else
4579         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4580     }
4581   mcIdType oldNbOfNodes(getNumberOfNodes());
4582   MCAuto<DataArrayDouble> newCoords;
4583   switch(policy)
4584   {
4585     case 0:
4586       {
4587         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4588         break;
4589       }
4590     case 1:
4591       {
4592         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4593         break;
4594       }
4595     default:
4596       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4597   }
4598   setCoords(newCoords);
4599   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4600   updateTime();
4601   return ret.retn();
4602 }
4603
4604
4605 /*!
4606  * Checks if \a this mesh is constituted by only quadratic cells.
4607  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4608  *  \throw If the coordinates array is not set.
4609  *  \throw If the nodal connectivity of cells is not defined.
4610  */
4611 bool MEDCouplingUMesh::isFullyQuadratic() const
4612 {
4613   checkFullyDefined();
4614   bool ret=true;
4615   mcIdType nbOfCells=getNumberOfCells();
4616   for(mcIdType i=0;i<nbOfCells && ret;i++)
4617     {
4618       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4619       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4620       ret=cm.isQuadratic();
4621     }
4622   return ret;
4623 }
4624
4625 /*!
4626  * Checks if \a this mesh includes any quadratic cell.
4627  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4628  *  \throw If the coordinates array is not set.
4629  *  \throw If the nodal connectivity of cells is not defined.
4630  */
4631 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4632 {
4633   checkFullyDefined();
4634   bool ret=false;
4635   mcIdType nbOfCells=getNumberOfCells();
4636   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4637     {
4638       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4639       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4640       ret=cm.isQuadratic();
4641     }
4642   return ret;
4643 }
4644
4645 /*!
4646  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4647  * this mesh, it remains unchanged.
4648  *  \throw If the coordinates array is not set.
4649  *  \throw If the nodal connectivity of cells is not defined.
4650  */
4651 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4652 {
4653   checkFullyDefined();
4654   mcIdType nbOfCells=getNumberOfCells();
4655   mcIdType delta=0;
4656   const mcIdType *iciptr=_nodal_connec_index->begin();
4657   for(mcIdType i=0;i<nbOfCells;i++)
4658     {
4659       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4660       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4661       if(cm.isQuadratic())
4662         {
4663           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4664           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4665           if(!cml.isDynamic())
4666             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4667           else
4668             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4669         }
4670     }
4671   if(delta==0)
4672     return ;
4673   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4674   const mcIdType *icptr(_nodal_connec->begin());
4675   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4676   newConnI->alloc(nbOfCells+1,1);
4677   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4678   *ociptr=0;
4679   _types.clear();
4680   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4681     {
4682       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4683       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4684       if(!cm.isQuadratic())
4685         {
4686           _types.insert(type);
4687           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4688           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4689         }
4690       else
4691         {
4692           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4693           _types.insert(typel);
4694           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4695           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4696           if(cml.isDynamic())
4697             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4698           *ocptr++=ToIdType(typel);
4699           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4700           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4701         }
4702     }
4703   setConnectivity(newConn,newConnI,false);
4704 }
4705
4706 /*!
4707  * This method converts all linear cell in \a this to quadratic one.
4708  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4709  * 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)
4710  * 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.
4711  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4712  * end of the existing coordinates.
4713  *
4714  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4715  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4716  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4717  *
4718  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4719  *
4720  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4721  */
4722 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4723 {
4724   DataArrayIdType *conn=0,*connI=0;
4725   DataArrayDouble *coords=0;
4726   std::set<INTERP_KERNEL::NormalizedCellType> types;
4727   checkFullyDefined();
4728   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4729   MCAuto<DataArrayDouble> coordsSafe;
4730   int meshDim=getMeshDimension();
4731   switch(conversionType)
4732   {
4733     case 0:
4734       switch(meshDim)
4735       {
4736         case 1:
4737           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4738           connSafe=conn; connISafe=connI; coordsSafe=coords;
4739           break;
4740         case 2:
4741           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4742           connSafe=conn; connISafe=connI; coordsSafe=coords;
4743           break;
4744         case 3:
4745           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4746           connSafe=conn; connISafe=connI; coordsSafe=coords;
4747           break;
4748         default:
4749           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4750       }
4751       break;
4752         case 1:
4753           {
4754             switch(meshDim)
4755             {
4756               case 1:
4757                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4758                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4759                 break;
4760               case 2:
4761                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4762                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4763                 break;
4764               case 3:
4765                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4766                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4767                 break;
4768               default:
4769                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4770             }
4771             break;
4772           }
4773         default:
4774           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4775   }
4776   setConnectivity(connSafe,connISafe,false);
4777   _types=types;
4778   setCoords(coordsSafe);
4779   return ret.retn();
4780 }
4781
4782 /*!
4783  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4784  * so that the number of cells remains the same. Quadratic faces are converted to
4785  * polygons. This method works only for 2D meshes in
4786  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4787  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4788  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4789  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4790  *         a polylinized edge constituting the input polygon.
4791  *  \throw If the coordinates array is not set.
4792  *  \throw If the nodal connectivity of cells is not defined.
4793  *  \throw If \a this->getMeshDimension() != 2.
4794  *  \throw If \a this->getSpaceDimension() != 2.
4795  */
4796 void MEDCouplingUMesh::tessellate2D(double eps)
4797 {
4798   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4799   if(spaceDim!=2)
4800     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4801   switch(meshDim)
4802     {
4803     case 1:
4804       return tessellate2DCurveInternal(eps);
4805     case 2:
4806       return tessellate2DInternal(eps);
4807     default:
4808       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4809     }
4810 }
4811
4812 #if 0
4813 /*!
4814  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4815  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4816  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4817  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4818  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4819  * This method can be seen as the opposite method of colinearize2D.
4820  * 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
4821  * to avoid to modify the numbering of existing nodes.
4822  *
4823  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4824  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4825  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4826  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4827  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4828  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4829  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4830  *
4831  * \sa buildDescendingConnectivity2
4832  */
4833 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4834                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4835 {
4836   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4838   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4839   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4840     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4841   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4842     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4843   //DataArrayIdType *out0(0),*outi0(0);
4844   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4845   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4846   //out0s=out0s->buildUnique(); out0s->sort(true);
4847 }
4848 #endif
4849
4850
4851 /*!
4852  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4853  * In addition, returns an array mapping new cells to old ones. <br>
4854  * This method typically increases the number of cells in \a this mesh
4855  * but the number of nodes remains \b unchanged.
4856  * That's why the 3D splitting policies
4857  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4858  *  \param [in] policy - specifies a pattern used for splitting.
4859  * The semantic of \a policy is:
4860  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4861  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4862  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4863  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4864  *
4865  *
4866  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4867  *          an id of old cell producing it. The caller is to delete this array using
4868  *         decrRef() as it is no more needed.
4869  *
4870  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4871  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4872  *          and \a this->getMeshDimension() != 3.
4873  *  \throw If \a policy is not one of the four discussed above.
4874  *  \throw If the nodal connectivity of cells is not defined.
4875  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4876  */
4877 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4878 {
4879   switch(policy)
4880   {
4881     case 0:
4882       return simplexizePol0();
4883     case 1:
4884       return simplexizePol1();
4885     case INTERP_KERNEL::PLANAR_FACE_5:
4886         return simplexizePlanarFace5();
4887     case INTERP_KERNEL::PLANAR_FACE_6:
4888         return simplexizePlanarFace6();
4889     default:
4890       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)");
4891   }
4892 }
4893
4894 /*!
4895  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4896  * - 1D: INTERP_KERNEL::NORM_SEG2
4897  * - 2D: INTERP_KERNEL::NORM_TRI3
4898  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4899  *
4900  * This method is useful for users that need to use P1 field services as
4901  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4902  * All these methods need mesh support containing only simplex cells.
4903  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4904  *  \throw If the coordinates array is not set.
4905  *  \throw If the nodal connectivity of cells is not defined.
4906  *  \throw If \a this->getMeshDimension() < 1.
4907  */
4908 bool MEDCouplingUMesh::areOnlySimplexCells() const
4909 {
4910   checkFullyDefined();
4911   int mdim=getMeshDimension();
4912   if(mdim<1 || mdim>3)
4913     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4914   mcIdType nbCells=getNumberOfCells();
4915   const mcIdType *conn=_nodal_connec->begin();
4916   const mcIdType *connI=_nodal_connec_index->begin();
4917   for(mcIdType i=0;i<nbCells;i++)
4918     {
4919       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4920       if(!cm.isSimplex())
4921         return false;
4922     }
4923   return true;
4924 }
4925
4926
4927
4928 /*!
4929  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4930  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4931  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4932  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4933  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4934  * so it can be useful to call mergeNodes() before calling this method.
4935  *  \throw If \a this->getMeshDimension() <= 1.
4936  *  \throw If the coordinates array is not set.
4937  *  \throw If the nodal connectivity of cells is not defined.
4938  */
4939 void MEDCouplingUMesh::convertDegeneratedCells()
4940 {
4941   checkFullyDefined();
4942   if(getMeshDimension()<=1)
4943     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4944   mcIdType nbOfCells=getNumberOfCells();
4945   if(nbOfCells<1)
4946     return ;
4947   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4948   mcIdType *conn=_nodal_connec->getPointer();
4949   mcIdType *index=_nodal_connec_index->getPointer();
4950   mcIdType posOfCurCell=0;
4951   mcIdType newPos=0;
4952   mcIdType lgthOfCurCell;
4953   for(mcIdType i=0;i<nbOfCells;i++)
4954     {
4955       lgthOfCurCell=index[i+1]-posOfCurCell;
4956       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4957       mcIdType newLgth;
4958       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4959                                                                                                      conn+newPos+1,newLgth);
4960       conn[newPos]=newType;
4961       newPos+=newLgth+1;
4962       posOfCurCell=index[i+1];
4963       index[i+1]=newPos;
4964     }
4965   if(newPos!=initMeshLgth)
4966     _nodal_connec->reAlloc(newPos);
4967   computeTypes();
4968 }
4969
4970 /*!
4971  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4972  * A cell is flat in the following cases:
4973  *   - for a linear cell, all points in the connectivity are equal
4974  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4975  *   identical quadratic points
4976  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4977  *      this array using decrRef() as it is no more needed.
4978  */
4979 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4980 {
4981   checkFullyDefined();
4982   if(getMeshDimension()<=1)
4983     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4984   mcIdType nbOfCells=getNumberOfCells();
4985   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4986   if(nbOfCells<1)
4987     return ret.retn();
4988   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4989   mcIdType *conn=_nodal_connec->getPointer();
4990   mcIdType *index=_nodal_connec_index->getPointer();
4991   mcIdType posOfCurCell=0;
4992   mcIdType newPos=0;
4993   mcIdType lgthOfCurCell, nbDelCells(0);
4994   for(mcIdType i=0;i<nbOfCells;i++)
4995     {
4996       lgthOfCurCell=index[i+1]-posOfCurCell;
4997       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4998       mcIdType newLgth;
4999       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
5000                                                                                                      conn+newPos+1,newLgth);
5001       // Shall we delete the cell if it is completely degenerated:
5002       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
5003       if (delCell)
5004         {
5005           nbDelCells++;
5006           ret->pushBackSilent(i);
5007         }
5008       else   //if the cell is to be deleted, simply stay at the same place
5009         {
5010           conn[newPos]=newType;
5011           newPos+=newLgth+1;
5012         }
5013       posOfCurCell=index[i+1];
5014       index[i+1-nbDelCells]=newPos;
5015     }
5016   if(newPos!=initMeshLgth)
5017     _nodal_connec->reAlloc(newPos);
5018   const mcIdType nCellDel=ret->getNumberOfTuples();
5019   if (nCellDel)
5020     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
5021   computeTypes();
5022   return ret.retn();
5023 }
5024
5025 /*!
5026  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
5027  * Only connectivity is considered here.
5028  */
5029 bool MEDCouplingUMesh::removeDegenerated1DCells()
5030 {
5031   checkConnectivityFullyDefined();
5032   if(getMeshDimension()!=1)
5033     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
5034   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
5035   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
5036   {
5037     for(std::size_t i=0;i<nbCells;i++)
5038       {
5039         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5040         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5041           {
5042             if(conn[conni[i]+1]!=conn[conni[i]+2])
5043               {
5044                 newSize++;
5045                 newSize2+=conni[i+1]-conni[i];
5046               }
5047           }
5048         else
5049           {
5050             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5051             throw INTERP_KERNEL::Exception(oss.str());
5052           }
5053       }
5054   }
5055   if(newSize==nbCells)//no cells has been removed -> do nothing
5056     return false;
5057   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5058   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5059   for(std::size_t i=0;i<nbCells;i++)
5060     {
5061       if(conn[conni[i]+1]!=conn[conni[i]+2])
5062         {
5063           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5064           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5065           newConnIPtr++;
5066         }
5067     }
5068   setConnectivity(newConn,newConnI,true);
5069   return true;
5070 }
5071
5072 /*!
5073  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5074  * A cell is considered to be oriented correctly if an angle between its
5075  * normal vector and a given vector is less than \c PI / \c 2.
5076  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5077  *         cells.
5078  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5079  *         checked.
5080  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5081  *         is not cleared before filling in.
5082  *  \throw If \a this->getMeshDimension() != 2.
5083  *  \throw If \a this->getSpaceDimension() != 3.
5084  *
5085  *  \if ENABLE_EXAMPLES
5086  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5087  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5088  *  \endif
5089  */
5090 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5091 {
5092   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5093     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5094   mcIdType nbOfCells=getNumberOfCells();
5095   const mcIdType *conn=_nodal_connec->begin();
5096   const mcIdType *connI=_nodal_connec_index->begin();
5097   const double *coordsPtr=_coords->begin();
5098   for(mcIdType i=0;i<nbOfCells;i++)
5099     {
5100       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5101       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5102         {
5103           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5104           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5105             cells.push_back(i);
5106         }
5107     }
5108 }
5109
5110 /*!
5111  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5112  * considered to be oriented correctly if an angle between its normal vector and a
5113  * given vector is less than \c PI / \c 2.
5114  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5115  *         cells.
5116  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5117  *         checked.
5118  *  \throw If \a this->getMeshDimension() != 2.
5119  *  \throw If \a this->getSpaceDimension() != 3.
5120  *
5121  *  \if ENABLE_EXAMPLES
5122  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5123  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5124  *  \endif
5125  *
5126  *  \sa changeOrientationOfCells
5127  */
5128 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5129 {
5130   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5131     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5132   mcIdType nbOfCells=getNumberOfCells();
5133   mcIdType *conn(_nodal_connec->getPointer());
5134   const mcIdType *connI(_nodal_connec_index->begin());
5135   const double *coordsPtr(_coords->begin());
5136   bool isModified(false);
5137   for(mcIdType i=0;i<nbOfCells;i++)
5138     {
5139       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5140       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5141         {
5142           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5143           bool isQuadratic(cm.isQuadratic());
5144           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5145             {
5146               isModified=true;
5147               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5148             }
5149         }
5150     }
5151   if(isModified)
5152     _nodal_connec->declareAsNew();
5153   updateTime();
5154 }
5155
5156 /*!
5157  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5158  *
5159  * \sa orientCorrectly2DCells
5160  */
5161 void MEDCouplingUMesh::changeOrientationOfCells()
5162 {
5163   int mdim(getMeshDimension());
5164   if(mdim!=2 && mdim!=1)
5165     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5166   mcIdType nbOfCells=getNumberOfCells();
5167   mcIdType *conn(_nodal_connec->getPointer());
5168   const mcIdType *connI(_nodal_connec_index->begin());
5169   if(mdim==2)
5170     {//2D
5171       for(mcIdType i=0;i<nbOfCells;i++)
5172         {
5173           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5174           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5175           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5176         }
5177     }
5178   else
5179     {//1D
5180       for(mcIdType i=0;i<nbOfCells;i++)
5181         {
5182           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5183           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5184           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5185         }
5186     }
5187 }
5188
5189 /*!
5190  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5191  * oriented facets. The normal vector of the facet should point out of the cell.
5192  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5193  *         is not cleared before filling in.
5194  *  \throw If \a this->getMeshDimension() != 3.
5195  *  \throw If \a this->getSpaceDimension() != 3.
5196  *  \throw If the coordinates array is not set.
5197  *  \throw If the nodal connectivity of cells is not defined.
5198  *
5199  *  \if ENABLE_EXAMPLES
5200  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5201  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5202  *  \endif
5203  */
5204 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5205 {
5206   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5207     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5208   mcIdType nbOfCells=getNumberOfCells();
5209   const mcIdType *conn=_nodal_connec->begin();
5210   const mcIdType *connI=_nodal_connec_index->begin();
5211   const double *coordsPtr=_coords->begin();
5212   for(mcIdType i=0;i<nbOfCells;i++)
5213     {
5214       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5215       if(type==INTERP_KERNEL::NORM_POLYHED)
5216         {
5217           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5218             cells.push_back(i);
5219         }
5220     }
5221 }
5222
5223 /*!
5224  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5225  * out of the cell.
5226  *  \throw If \a this->getMeshDimension() != 3.
5227  *  \throw If \a this->getSpaceDimension() != 3.
5228  *  \throw If the coordinates array is not set.
5229  *  \throw If the nodal connectivity of cells is not defined.
5230  *  \throw If the reparation fails.
5231  *
5232  *  \if ENABLE_EXAMPLES
5233  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5234  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5235  *  \endif
5236  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5237  */
5238 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5239 {
5240   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5241     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5242   mcIdType nbOfCells=getNumberOfCells();
5243   mcIdType *conn=_nodal_connec->getPointer();
5244   const mcIdType *connI=_nodal_connec_index->begin();
5245   const double *coordsPtr=_coords->begin();
5246   for(mcIdType i=0;i<nbOfCells;i++)
5247     {
5248       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5249       if(type==INTERP_KERNEL::NORM_POLYHED)
5250         {
5251           try
5252           {
5253               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5254                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5255           }
5256           catch(INTERP_KERNEL::Exception& e)
5257           {
5258               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5259               throw INTERP_KERNEL::Exception(oss.str());
5260           }
5261         }
5262     }
5263   updateTime();
5264 }
5265
5266 /*!
5267  * This method invert orientation of all cells in \a this.
5268  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5269  * This method only operates on the connectivity so coordinates are not touched at all.
5270  */
5271 void MEDCouplingUMesh::invertOrientationOfAllCells()
5272 {
5273   checkConnectivityFullyDefined();
5274   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5275   mcIdType *conn(_nodal_connec->getPointer());
5276   const mcIdType *conni(_nodal_connec_index->begin());
5277   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5278     {
5279       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5280       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5281       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5282         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5283     }
5284   updateTime();
5285 }
5286
5287 /*!
5288  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5289  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5290  * according to which the first facet of the cell should be oriented to have the normal vector
5291  * pointing out of cell.
5292  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5293  *         cells. The caller is to delete this array using decrRef() as it is no more
5294  *         needed.
5295  *  \throw If \a this->getMeshDimension() != 3.
5296  *  \throw If \a this->getSpaceDimension() != 3.
5297  *  \throw If the coordinates array is not set.
5298  *  \throw If the nodal connectivity of cells is not defined.
5299  *
5300  *  \if ENABLE_EXAMPLES
5301  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5302  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5303  *  \endif
5304  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5305  */
5306 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5307 {
5308   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5309   if(getMeshDimension()!=3)
5310     throw INTERP_KERNEL::Exception(msg);
5311   int spaceDim=getSpaceDimension();
5312   if(spaceDim!=3)
5313     throw INTERP_KERNEL::Exception(msg);
5314   //
5315   mcIdType nbOfCells=getNumberOfCells();
5316   mcIdType *conn=_nodal_connec->getPointer();
5317   const mcIdType *connI=_nodal_connec_index->begin();
5318   const double *coo=getCoords()->begin();
5319   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5320   for(mcIdType i=0;i<nbOfCells;i++)
5321     {
5322       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5323       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5324         {
5325           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5326             {
5327               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5328               cells->pushBackSilent(i);
5329             }
5330         }
5331     }
5332   return cells.retn();
5333 }
5334
5335 /*!
5336  * This method is a faster method to correct orientation of all 3D cells in \a this.
5337  * 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.
5338  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5339  *
5340  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5341  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5342  */
5343 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5344 {
5345   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5346     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5347   mcIdType nbOfCells=getNumberOfCells();
5348   mcIdType *conn=_nodal_connec->getPointer();
5349   const mcIdType *connI=_nodal_connec_index->begin();
5350   const double *coordsPtr=_coords->begin();
5351   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5352   for(mcIdType i=0;i<nbOfCells;i++)
5353     {
5354       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5355       switch(type)
5356       {
5357         case INTERP_KERNEL::NORM_TETRA4:
5358           {
5359             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5360               {
5361                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5362                 ret->pushBackSilent(i);
5363               }
5364             break;
5365           }
5366         case INTERP_KERNEL::NORM_PYRA5:
5367           {
5368             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5369               {
5370                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5371                 ret->pushBackSilent(i);
5372               }
5373             break;
5374           }
5375         case INTERP_KERNEL::NORM_PENTA6:
5376         case INTERP_KERNEL::NORM_HEXA8:
5377         case INTERP_KERNEL::NORM_HEXGP12:
5378           {
5379             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5380               {
5381                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5382                 ret->pushBackSilent(i);
5383               }
5384             break;
5385           }
5386         case INTERP_KERNEL::NORM_POLYHED:
5387           {
5388             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5389               {
5390                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5391                 ret->pushBackSilent(i);
5392               }
5393             break;
5394           }
5395         default:
5396           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 !");
5397       }
5398     }
5399   updateTime();
5400   return ret.retn();
5401 }
5402
5403 /*!
5404  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5405  * If it is not the case an exception will be thrown.
5406  * This method is fast because the first cell of \a this is used to compute the plane.
5407  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5408  * \param pos output of size at least 3 used to store a point owned of searched plane.
5409  */
5410 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5411 {
5412   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5413     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5414   const mcIdType *conn=_nodal_connec->begin();
5415   const mcIdType *connI=_nodal_connec_index->begin();
5416   const double *coordsPtr=_coords->begin();
5417   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5418   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5419 }
5420
5421 /*!
5422  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5423  * cells. Currently cells of the following types are treated:
5424  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5425  * For a cell of other type an exception is thrown.
5426  * Space dimension of a 2D mesh can be either 2 or 3.
5427  * The Edge Ratio of a cell \f$t\f$ is:
5428  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5429  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5430  *  the smallest edge lengths of \f$t\f$.
5431  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5432  *          cells and one time, lying on \a this mesh. The caller is to delete this
5433  *          field using decrRef() as it is no more needed.
5434  *  \throw If the coordinates array is not set.
5435  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5436  *  \throw If the connectivity data array has more than one component.
5437  *  \throw If the connectivity data array has a named component.
5438  *  \throw If the connectivity index data array has more than one component.
5439  *  \throw If the connectivity index data array has a named component.
5440  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5441  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5442  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5443  */
5444 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5445 {
5446   checkConsistencyLight();
5447   int spaceDim=getSpaceDimension();
5448   int meshDim=getMeshDimension();
5449   if(spaceDim!=2 && spaceDim!=3)
5450     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5451   if(meshDim!=2 && meshDim!=3)
5452     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5453   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5454   ret->setMesh(this);
5455   mcIdType nbOfCells=getNumberOfCells();
5456   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5457   arr->alloc(nbOfCells,1);
5458   double *pt=arr->getPointer();
5459   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5460   const mcIdType *conn=_nodal_connec->begin();
5461   const mcIdType *connI=_nodal_connec_index->begin();
5462   const double *coo=_coords->begin();
5463   double tmp[12];
5464   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5465     {
5466       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5467       switch(t)
5468       {
5469         case INTERP_KERNEL::NORM_TRI3:
5470           {
5471             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5472             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5473             break;
5474           }
5475         case INTERP_KERNEL::NORM_QUAD4:
5476           {
5477             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5478             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5479             break;
5480           }
5481         case INTERP_KERNEL::NORM_TETRA4:
5482           {
5483             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5484             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5485             break;
5486           }
5487         default:
5488           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5489       }
5490       conn+=connI[i+1]-connI[i];
5491     }
5492   ret->setName("EdgeRatio");
5493   ret->synchronizeTimeWithSupport();
5494   return ret.retn();
5495 }
5496
5497 /*!
5498  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5499  * cells. Currently cells of the following types are treated:
5500  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5501  * For a cell of other type an exception is thrown.
5502  * Space dimension of a 2D mesh can be either 2 or 3.
5503  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5504  *          cells and one time, lying on \a this mesh. The caller is to delete this
5505  *          field using decrRef() as it is no more needed.
5506  *  \throw If the coordinates array is not set.
5507  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5508  *  \throw If the connectivity data array has more than one component.
5509  *  \throw If the connectivity data array has a named component.
5510  *  \throw If the connectivity index data array has more than one component.
5511  *  \throw If the connectivity index data array has a named component.
5512  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5513  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5514  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5515  */
5516 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5517 {
5518   checkConsistencyLight();
5519   int spaceDim=getSpaceDimension();
5520   int meshDim=getMeshDimension();
5521   if(spaceDim!=2 && spaceDim!=3)
5522     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5523   if(meshDim!=2 && meshDim!=3)
5524     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5525   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5526   ret->setMesh(this);
5527   mcIdType nbOfCells=getNumberOfCells();
5528   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5529   arr->alloc(nbOfCells,1);
5530   double *pt=arr->getPointer();
5531   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5532   const mcIdType *conn=_nodal_connec->begin();
5533   const mcIdType *connI=_nodal_connec_index->begin();
5534   const double *coo=_coords->begin();
5535   double tmp[12];
5536   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5537     {
5538       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5539       switch(t)
5540       {
5541         case INTERP_KERNEL::NORM_TRI3:
5542           {
5543             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5544             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5545             break;
5546           }
5547         case INTERP_KERNEL::NORM_QUAD4:
5548           {
5549             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5550             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5551             break;
5552           }
5553         case INTERP_KERNEL::NORM_TETRA4:
5554           {
5555             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5556             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5557             break;
5558           }
5559         default:
5560           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5561       }
5562       conn+=connI[i+1]-connI[i];
5563     }
5564   ret->setName("AspectRatio");
5565   ret->synchronizeTimeWithSupport();
5566   return ret.retn();
5567 }
5568
5569 /*!
5570  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5571  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5572  * in 3D space. Currently only cells of the following types are
5573  * treated: INTERP_KERNEL::NORM_QUAD4.
5574  * For a cell of other type an exception is thrown.
5575  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5576  * Defining
5577  * \f$t=\vec{da}\times\vec{ab}\f$,
5578  * \f$u=\vec{ab}\times\vec{bc}\f$
5579  * \f$v=\vec{bc}\times\vec{cd}\f$
5580  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5581  *  \f[
5582  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5583  *  \f]
5584  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5585  *          cells and one time, lying on \a this mesh. The caller is to delete this
5586  *          field using decrRef() as it is no more needed.
5587  *  \throw If the coordinates array is not set.
5588  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5589  *  \throw If the connectivity data array has more than one component.
5590  *  \throw If the connectivity data array has a named component.
5591  *  \throw If the connectivity index data array has more than one component.
5592  *  \throw If the connectivity index data array has a named component.
5593  *  \throw If \a this->getMeshDimension() != 2.
5594  *  \throw If \a this->getSpaceDimension() != 3.
5595  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5596  */
5597 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5598 {
5599   checkConsistencyLight();
5600   int spaceDim=getSpaceDimension();
5601   int meshDim=getMeshDimension();
5602   if(spaceDim!=3)
5603     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5604   if(meshDim!=2)
5605     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5606   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5607   ret->setMesh(this);
5608   mcIdType nbOfCells=getNumberOfCells();
5609   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5610   arr->alloc(nbOfCells,1);
5611   double *pt=arr->getPointer();
5612   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5613   const mcIdType *conn=_nodal_connec->begin();
5614   const mcIdType *connI=_nodal_connec_index->begin();
5615   const double *coo=_coords->begin();
5616   double tmp[12];
5617   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5618     {
5619       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5620       switch(t)
5621       {
5622         case INTERP_KERNEL::NORM_QUAD4:
5623           {
5624             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5625             *pt=INTERP_KERNEL::quadWarp(tmp);
5626             break;
5627           }
5628         default:
5629           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5630       }
5631       conn+=connI[i+1]-connI[i];
5632     }
5633   ret->setName("Warp");
5634   ret->synchronizeTimeWithSupport();
5635   return ret.retn();
5636 }
5637
5638
5639 /*!
5640  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5641  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5642  * treated: INTERP_KERNEL::NORM_QUAD4.
5643  * The skew is computed as follow for a quad with points (a,b,c,d): let
5644  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5645  * then the skew is computed as:
5646  *  \f[
5647  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5648  *  \f]
5649  *
5650  * For a cell of other type an exception is thrown.
5651  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5652  *          cells and one time, lying on \a this mesh. The caller is to delete this
5653  *          field using decrRef() as it is no more needed.
5654  *  \throw If the coordinates array is not set.
5655  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5656  *  \throw If the connectivity data array has more than one component.
5657  *  \throw If the connectivity data array has a named component.
5658  *  \throw If the connectivity index data array has more than one component.
5659  *  \throw If the connectivity index data array has a named component.
5660  *  \throw If \a this->getMeshDimension() != 2.
5661  *  \throw If \a this->getSpaceDimension() != 3.
5662  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5663  */
5664 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5665 {
5666   checkConsistencyLight();
5667   int spaceDim=getSpaceDimension();
5668   int meshDim=getMeshDimension();
5669   if(spaceDim!=3)
5670     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5671   if(meshDim!=2)
5672     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5673   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5674   ret->setMesh(this);
5675   mcIdType nbOfCells=getNumberOfCells();
5676   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5677   arr->alloc(nbOfCells,1);
5678   double *pt=arr->getPointer();
5679   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5680   const mcIdType *conn=_nodal_connec->begin();
5681   const mcIdType *connI=_nodal_connec_index->begin();
5682   const double *coo=_coords->begin();
5683   double tmp[12];
5684   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5685     {
5686       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5687       switch(t)
5688       {
5689         case INTERP_KERNEL::NORM_QUAD4:
5690           {
5691             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5692             *pt=INTERP_KERNEL::quadSkew(tmp);
5693             break;
5694           }
5695         default:
5696           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5697       }
5698       conn+=connI[i+1]-connI[i];
5699     }
5700   ret->setName("Skew");
5701   ret->synchronizeTimeWithSupport();
5702   return ret.retn();
5703 }
5704
5705 /*!
5706  * 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.
5707  *
5708  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5709  *
5710  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5711  */
5712 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5713 {
5714   checkConsistencyLight();
5715   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5716   ret->setMesh(this);
5717   std::set<INTERP_KERNEL::NormalizedCellType> types;
5718   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5719   int spaceDim(getSpaceDimension());
5720   mcIdType nbCells(getNumberOfCells());
5721   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5722   arr->alloc(nbCells,1);
5723   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5724     {
5725       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5726       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5727       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5728     }
5729   ret->setArray(arr);
5730   ret->setName("Diameter");
5731   return ret.retn();
5732 }
5733
5734 /*!
5735  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5736  *
5737  * \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)
5738  *                         For all other cases this input parameter is ignored.
5739  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5740  *
5741  * \throw If \a this is not fully set (coordinates and connectivity).
5742  * \throw If a cell in \a this has no valid nodeId.
5743  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5744  */
5745 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5746 {
5747   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5748   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.
5749     return getBoundingBoxForBBTreeFast();
5750   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5751     {
5752       bool presenceOfQuadratic(false);
5753       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5754         {
5755           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5756           if(cm.isQuadratic())
5757             presenceOfQuadratic=true;
5758         }
5759       if(!presenceOfQuadratic)
5760         return getBoundingBoxForBBTreeFast();
5761       if(mDim==2 && sDim==2)
5762         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5763       else
5764         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5765     }
5766   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) !");
5767 }
5768
5769 /*!
5770  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5771  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5772  *
5773  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5774  *
5775  * \throw If \a this is not fully set (coordinates and connectivity).
5776  * \throw If a cell in \a this has no valid nodeId.
5777  */
5778 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5779 {
5780   checkFullyDefined();
5781   int spaceDim(getSpaceDimension());
5782   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5783   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5784   double *bbox(ret->getPointer());
5785   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5786     {
5787       bbox[2*i]=std::numeric_limits<double>::max();
5788       bbox[2*i+1]=-std::numeric_limits<double>::max();
5789     }
5790   const double *coordsPtr(_coords->begin());
5791   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5792   for(mcIdType i=0;i<nbOfCells;i++)
5793     {
5794       mcIdType offset=connI[i]+1;
5795       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5796       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5797         {
5798           mcIdType nodeId=conn[offset+j];
5799           if(nodeId>=0 && nodeId<nbOfNodes)
5800             {
5801               for(int k=0;k<spaceDim;k++)
5802                 {
5803                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5804                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5805                 }
5806               kk++;
5807             }
5808         }
5809       if(kk==0)
5810         {
5811           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5812           throw INTERP_KERNEL::Exception(oss.str());
5813         }
5814     }
5815   return ret.retn();
5816 }
5817
5818 /*!
5819  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5820  * useful for 2D meshes having quadratic cells
5821  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5822  * the two extremities of the arc of circle).
5823  *
5824  * \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)
5825  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5826  * \throw If \a this is not fully defined.
5827  * \throw If \a this is not a mesh with meshDimension equal to 2.
5828  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5829  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5830  */
5831 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5832 {
5833   checkFullyDefined();
5834   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5835
5836   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5837   mcIdType nbOfCells=getNumberOfCells();
5838   if(spaceDim!=2 || mDim!=2)
5839     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!");
5840   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5841   double *bbox(ret->getPointer());
5842   const double *coords(_coords->begin());
5843   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5844   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5845     {
5846       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5847       mcIdType sz(connI[1]-connI[0]-1);
5848       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5849       INTERP_KERNEL::QuadraticPolygon *pol(0);
5850       for(mcIdType j=0;j<sz;j++)
5851         {
5852           mcIdType nodeId(conn[*connI+1+j]);
5853           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5854         }
5855       if(!cm.isQuadratic())
5856         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5857       else
5858         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5859       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5860       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5861     }
5862   return ret.retn();
5863 }
5864
5865 /*!
5866  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5867  * useful for 2D meshes having quadratic cells
5868  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5869  * the two extremities of the arc of circle).
5870  *
5871  * \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)
5872  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5873  * \throw If \a this is not fully defined.
5874  * \throw If \a this is not a mesh with meshDimension equal to 1.
5875  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5876  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5877  */
5878 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5879 {
5880   checkFullyDefined();
5881   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5882   mcIdType nbOfCells=getNumberOfCells();
5883   if(spaceDim!=2 || mDim!=1)
5884     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!");
5885   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5886   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5887   double *bbox(ret->getPointer());
5888   const double *coords(_coords->begin());
5889   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5890   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5891     {
5892       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5893       mcIdType sz(connI[1]-connI[0]-1);
5894       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5895       INTERP_KERNEL::Edge *edge(0);
5896       for(mcIdType j=0;j<sz;j++)
5897         {
5898           mcIdType nodeId(conn[*connI+1+j]);
5899           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5900         }
5901       if(!cm.isQuadratic())
5902         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5903       else
5904         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5905       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5906       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5907     }
5908   return ret.retn();
5909 }
5910
5911 /// @cond INTERNAL
5912
5913 namespace MEDCouplingImpl
5914 {
5915   class ConnReader
5916   {
5917   public:
5918     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5919     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5920   private:
5921     const mcIdType *_conn;
5922     mcIdType _val;
5923   };
5924
5925   class ConnReader2
5926   {
5927   public:
5928     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5929     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5930   private:
5931     const mcIdType *_conn;
5932     mcIdType _val;
5933   };
5934 }
5935
5936 /// @endcond
5937
5938 /*!
5939  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5940  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5941  * \a this is composed in cell types.
5942  * The returned array is of size 3*n where n is the number of different types present in \a this.
5943  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5944  * This parameter is kept only for compatibility with other method listed above.
5945  */
5946 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5947 {
5948   checkConnectivityFullyDefined();
5949   const mcIdType *conn=_nodal_connec->begin();
5950   const mcIdType *connI=_nodal_connec_index->begin();
5951   const mcIdType *work=connI;
5952   mcIdType nbOfCells=getNumberOfCells();
5953   std::size_t n=getAllGeoTypes().size();
5954   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5955   std::set<INTERP_KERNEL::NormalizedCellType> types;
5956   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5957     {
5958       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5959       if(types.find(typ)!=types.end())
5960         {
5961           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5962           oss << " is not contiguous !";
5963           throw INTERP_KERNEL::Exception(oss.str());
5964         }
5965       types.insert(typ);
5966       ret[3*i]=typ;
5967       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5968       ret[3*i+1]=ToIdType(std::distance(work,work2));
5969       work=work2;
5970     }
5971   return ret;
5972 }
5973
5974 /*!
5975  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5976  * only for types cell, type node is not managed.
5977  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5978  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5979  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5980  * If 2 or more same geometric type is in \a code and exception is thrown too.
5981  *
5982  * This method firstly checks
5983  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5984  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5985  * an exception is thrown too.
5986  *
5987  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5988  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5989  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5990  */
5991 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5992 {
5993   if(code.empty())
5994     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5995   std::size_t sz=code.size();
5996   std::size_t n=sz/3;
5997   if(sz%3!=0)
5998     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5999   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6000   mcIdType nb=0;
6001   bool isNoPflUsed=true;
6002   for(std::size_t i=0;i<n;i++)
6003     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6004       {
6005         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6006         nb+=code[3*i+1];
6007         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6008           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6009         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6010       }
6011   if(types.size()!=n)
6012     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6013   if(isNoPflUsed)
6014     {
6015       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6016         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6017       if(types.size()==_types.size())
6018         return 0;
6019     }
6020   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
6021   ret->alloc(nb,1);
6022   mcIdType *retPtr=ret->getPointer();
6023   const mcIdType *connI=_nodal_connec_index->begin();
6024   const mcIdType *conn=_nodal_connec->begin();
6025   mcIdType nbOfCells=getNumberOfCells();
6026   const mcIdType *i=connI;
6027   int kk=0;
6028   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6029     {
6030       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
6031       mcIdType offset=ToIdType(std::distance(connI,i));
6032       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
6033       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
6034       if(code[3*kk+2]==-1)
6035         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
6036           *retPtr++=k+offset;
6037       else
6038         {
6039           mcIdType idInIdsPerType=code[3*kk+2];
6040           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6041             {
6042               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6043               if(zePfl)
6044                 {
6045                   zePfl->checkAllocated();
6046                   if(zePfl->getNumberOfComponents()==1)
6047                     {
6048                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6049                         {
6050                           if(*k>=0 && *k<nbOfCellsOfCurType)
6051                             *retPtr=(*k)+offset;
6052                           else
6053                             {
6054                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6055                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6056                               throw INTERP_KERNEL::Exception(oss.str());
6057                             }
6058                         }
6059                     }
6060                   else
6061                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6062                 }
6063               else
6064                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6065             }
6066           else
6067             {
6068               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6069               oss << " should be in [0," << idsPerType.size() << ") !";
6070               throw INTERP_KERNEL::Exception(oss.str());
6071             }
6072         }
6073       i=j;
6074     }
6075   return ret.retn();
6076 }
6077
6078 /*!
6079  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6080  * 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.
6081  * 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.
6082  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6083  *
6084  * \param [in] profile list of IDs constituing the profile
6085  * \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.
6086  * \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,
6087  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6088  * \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.
6089  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6090  * \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
6091  */
6092 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6093 {
6094   if(!profile)
6095     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6096   if(profile->getNumberOfComponents()!=1)
6097     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6098   checkConnectivityFullyDefined();
6099   const mcIdType *conn=_nodal_connec->begin();
6100   const mcIdType *connI=_nodal_connec_index->begin();
6101   mcIdType nbOfCells=getNumberOfCells();
6102   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6103   std::vector<mcIdType> typeRangeVals(1);
6104   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6105     {
6106       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6107       if(std::find(types.begin(),types.end(),curType)!=types.end())
6108         {
6109           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6110         }
6111       types.push_back(curType);
6112       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6113       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6114     }
6115   //
6116   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6117   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6118   MCAuto<DataArrayIdType> tmp0=castArr;
6119   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6120   MCAuto<DataArrayIdType> tmp2=castsPresent;
6121   //
6122   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6123   code.resize(3*nbOfCastsFinal);
6124   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6125   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6126   for(mcIdType i=0;i<nbOfCastsFinal;i++)
6127     {
6128       mcIdType castId=castsPresent->getIJ(i,0);
6129       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6130       idsInPflPerType2.push_back(tmp3);
6131       code[3*i]=ToIdType(types[castId]);
6132       code[3*i+1]=tmp3->getNumberOfTuples();
6133       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6134       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6135         {
6136           tmp4->copyStringInfoFrom(*profile);
6137           idsPerType2.push_back(tmp4);
6138           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6139         }
6140       else
6141         {
6142           code[3*i+2]=-1;
6143         }
6144     }
6145   std::size_t sz2=idsInPflPerType2.size();
6146   idsInPflPerType.resize(sz2);
6147   for(std::size_t i=0;i<sz2;i++)
6148     {
6149       DataArrayIdType *locDa=idsInPflPerType2[i];
6150       locDa->incrRef();
6151       idsInPflPerType[i]=locDa;
6152     }
6153   std::size_t sz=idsPerType2.size();
6154   idsPerType.resize(sz);
6155   for(std::size_t i=0;i<sz;i++)
6156     {
6157       DataArrayIdType *locDa=idsPerType2[i];
6158       locDa->incrRef();
6159       idsPerType[i]=locDa;
6160     }
6161 }
6162
6163 /*!
6164  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6165  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6166  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6167  * 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.
6168  */
6169 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6170 {
6171   checkFullyDefined();
6172   nM1LevMesh->checkFullyDefined();
6173   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6174     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6175   if(_coords!=nM1LevMesh->getCoords())
6176     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6177   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6178   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6179   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6180   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6181   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6182   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6183   tmp->setConnectivity(tmp0,tmp1);
6184   tmp->renumberCells(ret0->begin(),false);
6185   revDesc=tmp->getNodalConnectivity();
6186   revDescIndx=tmp->getNodalConnectivityIndex();
6187   DataArrayIdType *ret=0;
6188   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6189     {
6190       mcIdType tmp2;
6191       ret->getMaxValue(tmp2);
6192       ret->decrRef();
6193       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6194       throw INTERP_KERNEL::Exception(oss.str());
6195     }
6196   nM1LevMeshIds=ret;
6197   //
6198   revDesc->incrRef();
6199   revDescIndx->incrRef();
6200   ret1->incrRef();
6201   ret0->incrRef();
6202   meshnM1Old2New=ret0;
6203   return ret1;
6204 }
6205
6206 /*!
6207  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6208  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6209  * in "Old to New" mode.
6210  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6211  *          this array using decrRef() as it is no more needed.
6212  *  \throw If the nodal connectivity of cells is not defined.
6213  */
6214 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6215 {
6216   checkConnectivityFullyDefined();
6217   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6218   renumberCells(ret->begin(),false);
6219   return ret.retn();
6220 }
6221
6222 /*!
6223  * This methods checks that cells are sorted by their types.
6224  * This method makes asumption (no check) that connectivity is correctly set before calling.
6225  */
6226 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6227 {
6228   checkFullyDefined();
6229   const mcIdType *conn=_nodal_connec->begin();
6230   const mcIdType *connI=_nodal_connec_index->begin();
6231   mcIdType nbOfCells=getNumberOfCells();
6232   std::set<INTERP_KERNEL::NormalizedCellType> types;
6233   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6234     {
6235       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6236       if(types.find(curType)!=types.end())
6237         return false;
6238       types.insert(curType);
6239       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6240     }
6241   return true;
6242 }
6243
6244 /*!
6245  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6246  * The geometric type order is specified by MED file.
6247  *
6248  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6249  */
6250 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6251 {
6252   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6253 }
6254
6255 /*!
6256  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6257  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6258  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6259  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6260  */
6261 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6262 {
6263   checkFullyDefined();
6264   const mcIdType *conn=_nodal_connec->begin();
6265   const mcIdType *connI=_nodal_connec_index->begin();
6266   mcIdType nbOfCells=getNumberOfCells();
6267   if(nbOfCells==0)
6268     return true;
6269   mcIdType lastPos=-1;
6270   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6271   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6272     {
6273       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6274       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6275       if(isTypeExists!=orderEnd)
6276         {
6277           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6278           if(pos<=lastPos)
6279             return false;
6280           lastPos=pos;
6281           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6282         }
6283       else
6284         {
6285           if(sg.find(curType)==sg.end())
6286             {
6287               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6288               sg.insert(curType);
6289             }
6290           else
6291             return false;
6292         }
6293     }
6294   return true;
6295 }
6296
6297 /*!
6298  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6299  * 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
6300  * 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'.
6301  */
6302 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6303 {
6304   checkConnectivityFullyDefined();
6305   mcIdType nbOfCells=getNumberOfCells();
6306   const mcIdType *conn=_nodal_connec->begin();
6307   const mcIdType *connI=_nodal_connec_index->begin();
6308   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6309   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6310   tmpa->alloc(nbOfCells,1);
6311   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6312   tmpb->fillWithZero();
6313   mcIdType *tmp=tmpa->getPointer();
6314   mcIdType *tmp2=tmpb->getPointer();
6315   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6316     {
6317       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6318       if(where!=orderEnd)
6319         {
6320           mcIdType pos=ToIdType(std::distance(orderBg,where));
6321           tmp2[pos]++;
6322           tmp[std::distance(connI,i)]=pos;
6323         }
6324       else
6325         {
6326           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6327           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6328           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6329           throw INTERP_KERNEL::Exception(oss.str());
6330         }
6331     }
6332   nbPerType=tmpb.retn();
6333   return tmpa.retn();
6334 }
6335
6336 /*!
6337  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6338  *
6339  * \return a new object containing the old to new correspondence.
6340  *
6341  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6342  */
6343 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6344 {
6345   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6346 }
6347
6348 /*!
6349  * 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.
6350  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6351  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6352  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6353  */
6354 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6355 {
6356   DataArrayIdType *nbPerType=0;
6357   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6358   nbPerType->decrRef();
6359   return tmpa->buildPermArrPerLevel();
6360 }
6361
6362 /*!
6363  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6364  * The number of cells remains unchanged after the call of this method.
6365  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6366  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6367  *
6368  * \return the array giving the correspondence old to new.
6369  */
6370 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6371 {
6372   checkFullyDefined();
6373   computeTypes();
6374   const mcIdType *conn=_nodal_connec->begin();
6375   const mcIdType *connI=_nodal_connec_index->begin();
6376   mcIdType nbOfCells=getNumberOfCells();
6377   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6378   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6379     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6380       {
6381         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6382         types.push_back(curType);
6383         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6384       }
6385   DataArrayIdType *ret=DataArrayIdType::New();
6386   ret->alloc(nbOfCells,1);
6387   mcIdType *retPtr=ret->getPointer();
6388   std::fill(retPtr,retPtr+nbOfCells,-1);
6389   mcIdType newCellId=0;
6390   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6391     {
6392       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6393         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6394           retPtr[std::distance(connI,i)]=newCellId++;
6395     }
6396   renumberCells(retPtr,false);
6397   return ret;
6398 }
6399
6400 /*!
6401  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6402  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6403  * This method makes asumption that connectivity is correctly set before calling.
6404  */
6405 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6406 {
6407   checkConnectivityFullyDefined();
6408   const mcIdType *conn=_nodal_connec->begin();
6409   const mcIdType *connI=_nodal_connec_index->begin();
6410   mcIdType nbOfCells=getNumberOfCells();
6411   std::vector<MEDCouplingUMesh *> ret;
6412   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6413     {
6414       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6415       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6416       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6417       mcIdType endCellId=ToIdType(std::distance(connI,i));
6418       mcIdType sz=endCellId-beginCellId;
6419       mcIdType *cells=new mcIdType[sz];
6420       for(mcIdType j=0;j<sz;j++)
6421         cells[j]=beginCellId+j;
6422       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6423       delete [] cells;
6424       ret.push_back(m);
6425     }
6426   return ret;
6427 }
6428
6429 /*!
6430  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6431  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6432  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6433  *
6434  * \return a newly allocated instance, that the caller must manage.
6435  * \throw If \a this contains more than one geometric type.
6436  * \throw If the nodal connectivity of \a this is not fully defined.
6437  * \throw If the internal data is not coherent.
6438  */
6439 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6440 {
6441   checkConnectivityFullyDefined();
6442   if(_types.size()!=1)
6443     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6444   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6445   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6446   ret->setCoords(getCoords());
6447   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6448   if(retC)
6449     {
6450       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6451       retC->setNodalConnectivity(c);
6452     }
6453   else
6454     {
6455       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6456       if(!retD)
6457         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6458       DataArrayIdType *c=0,*ci=0;
6459       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6460       MCAuto<DataArrayIdType> cs(c),cis(ci);
6461       retD->setNodalConnectivity(cs,cis);
6462     }
6463   return ret.retn();
6464 }
6465
6466 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6467 {
6468   checkConnectivityFullyDefined();
6469   if(_types.size()!=1)
6470     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6471   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6472   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6473   if(cm.isDynamic())
6474     {
6475       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6476       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6477       throw INTERP_KERNEL::Exception(oss.str());
6478     }
6479   mcIdType nbCells=getNumberOfCells();
6480   mcIdType typi=ToIdType(typ);
6481   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6482   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6483   mcIdType *outPtr=connOut->getPointer();
6484   const mcIdType *conn=_nodal_connec->begin();
6485   const mcIdType *connI=_nodal_connec_index->begin();
6486   nbNodesPerCell++;
6487   for(mcIdType i=0;i<nbCells;i++,connI++)
6488     {
6489       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6490         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6491       else
6492         {
6493           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 << ") !";
6494           throw INTERP_KERNEL::Exception(oss.str());
6495         }
6496     }
6497   return connOut.retn();
6498 }
6499
6500 /*!
6501  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6502  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6503  * \param nodalConn nodal connectivity
6504  * \param nodalConnIndex nodal connectivity indices
6505  */
6506 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6507 {
6508   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6509   checkConnectivityFullyDefined();
6510   if(_types.size()!=1)
6511     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6512   mcIdType nbCells=getNumberOfCells(),
6513            lgth=_nodal_connec->getNumberOfTuples();
6514   if(lgth<nbCells)
6515     throw INTERP_KERNEL::Exception(msg0);
6516   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6517   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6518   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6519   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6520   cip[0]=0;
6521   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6522     {
6523       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6524       mcIdType delta(stop-strt);
6525       if(delta>=1)
6526         {
6527           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6528             cp=std::copy(incp+strt,incp+stop,cp);
6529           else
6530             throw INTERP_KERNEL::Exception(msg0);
6531         }
6532       else
6533         throw INTERP_KERNEL::Exception(msg0);
6534       cip[1]=cip[0]+delta;
6535     }
6536   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6537 }
6538
6539 /*!
6540  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6541  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6542  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6543  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6544  * are not used here to avoid the build of big permutation array.
6545  *
6546  * \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
6547  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6548  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6549  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6550  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6551  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6552  * \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
6553  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6554  */
6555 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6556                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6557                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6558 {
6559   std::vector<const MEDCouplingUMesh *> ms2;
6560   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6561     if(*it)
6562       {
6563         (*it)->checkConnectivityFullyDefined();
6564         ms2.push_back(*it);
6565       }
6566   if(ms2.empty())
6567     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6568   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6569   int meshDim=ms2[0]->getMeshDimension();
6570   std::vector<const MEDCouplingUMesh *> m1ssm;
6571   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6572   //
6573   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6574   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6575   mcIdType fake=0,rk=0;
6576   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6577   ret1->alloc(0,1); ret2->alloc(0,1);
6578   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6579     {
6580       if(meshDim!=(*it)->getMeshDimension())
6581         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6582       if(refCoo!=(*it)->getCoords())
6583         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6584       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6585       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6586       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6587       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6588         {
6589           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6590           m1ssmSingleAuto.push_back(singleCell);
6591           m1ssmSingle.push_back(singleCell);
6592           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6593         }
6594     }
6595   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6596   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6597   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6598   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6599     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6600   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6601   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6602   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6603   return ret0.retn();
6604 }
6605
6606 /*!
6607  * This method returns a newly created DataArrayIdType instance.
6608  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6609  */
6610 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6611 {
6612   checkFullyDefined();
6613   const mcIdType *conn=_nodal_connec->begin();
6614   const mcIdType *connIndex=_nodal_connec_index->begin();
6615   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6616   for(const mcIdType *w=begin;w!=end;w++)
6617     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6618       ret->pushBackSilent(*w);
6619   return ret.retn();
6620 }
6621
6622 /*!
6623  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6624  * are in [0:getNumberOfCells())
6625  */
6626 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6627 {
6628   checkFullyDefined();
6629   const mcIdType *conn=_nodal_connec->begin();
6630   const mcIdType *connI=_nodal_connec_index->begin();
6631   mcIdType nbOfCells=getNumberOfCells();
6632   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6633   mcIdType *tmp=new mcIdType[nbOfCells];
6634   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6635     {
6636       mcIdType j=0;
6637       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6638         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6639           tmp[std::distance(connI,i)]=j++;
6640     }
6641   DataArrayIdType *ret=DataArrayIdType::New();
6642   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6643   ret->copyStringInfoFrom(*da);
6644   mcIdType *retPtr=ret->getPointer();
6645   const mcIdType *daPtr=da->begin();
6646   mcIdType nbOfElems=da->getNbOfElems();
6647   for(mcIdType k=0;k<nbOfElems;k++)
6648     retPtr[k]=tmp[daPtr[k]];
6649   delete [] tmp;
6650   return ret;
6651 }
6652
6653 /*!
6654  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6655  * This method \b works \b for mesh sorted by type.
6656  * cells whose ids is in 'idsPerGeoType' array.
6657  * This method conserves coords and name of mesh.
6658  */
6659 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6660 {
6661   std::vector<mcIdType> code=getDistributionOfTypes();
6662   std::size_t nOfTypesInThis=code.size()/3;
6663   mcIdType sz=0,szOfType=0;
6664   for(std::size_t i=0;i<nOfTypesInThis;i++)
6665     {
6666       if(code[3*i]!=type)
6667         sz+=code[3*i+1];
6668       else
6669         szOfType=code[3*i+1];
6670     }
6671   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6672     if(*work<0 || *work>=szOfType)
6673       {
6674         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6675         oss << ". It should be in [0," << szOfType << ") !";
6676         throw INTERP_KERNEL::Exception(oss.str());
6677       }
6678   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6679   mcIdType *idsPtr=idsTokeep->getPointer();
6680   mcIdType offset=0;
6681   for(std::size_t i=0;i<nOfTypesInThis;i++)
6682     {
6683       if(code[3*i]!=type)
6684         for(mcIdType j=0;j<code[3*i+1];j++)
6685           *idsPtr++=offset+j;
6686       else
6687         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6688       offset+=code[3*i+1];
6689     }
6690   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6691   ret->copyTinyInfoFrom(this);
6692   return ret.retn();
6693 }
6694
6695 /*!
6696  * This method returns a vector of size 'this->getNumberOfCells()'.
6697  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6698  */
6699 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6700 {
6701   mcIdType ncell=getNumberOfCells();
6702   std::vector<bool> ret(ncell);
6703   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6704   const mcIdType *c=getNodalConnectivity()->begin();
6705   for(mcIdType i=0;i<ncell;i++)
6706     {
6707       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6708       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6709       ret[i]=cm.isQuadratic();
6710     }
6711   return ret;
6712 }
6713
6714 /*!
6715  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6716  */
6717 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6718 {
6719   if(other->getType()!=UNSTRUCTURED)
6720     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6721   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6722   return MergeUMeshes(this,otherC);
6723 }
6724
6725 /*!
6726  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6727  * computed by averaging coordinates of cell nodes, so this method is not a right
6728  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6729  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6730  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6731  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6732  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6733  *          components. The caller is to delete this array using decrRef() as it is
6734  *          no more needed.
6735  *  \throw If the coordinates array is not set.
6736  *  \throw If the nodal connectivity of cells is not defined.
6737  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6738  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6739  */
6740 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6741 {
6742   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6743   int spaceDim=getSpaceDimension();
6744   mcIdType nbOfCells=getNumberOfCells();
6745   ret->alloc(nbOfCells,spaceDim);
6746   ret->copyStringInfoFrom(*getCoords());
6747   double *ptToFill=ret->getPointer();
6748   const mcIdType *nodal=_nodal_connec->begin();
6749   const mcIdType *nodalI=_nodal_connec_index->begin();
6750   const double *coor=_coords->begin();
6751   for(mcIdType i=0;i<nbOfCells;i++)
6752     {
6753       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6754       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6755       ptToFill+=spaceDim;
6756     }
6757   return ret.retn();
6758 }
6759
6760
6761 /*!
6762  * See computeCellCenterOfMass().
6763  *  \param eps a precision for the detection of degenerated arc of circles.
6764  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6765  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6766  *          components. The caller is to delete this array using decrRef() as it is
6767  *          no more needed.
6768  *  \throw If the coordinates array is not set.
6769  *  \throw If the nodal connectivity of cells is not defined.
6770  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6771  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6772  */
6773 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6774 {
6775   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6776   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6777   return ret.retn();
6778 }
6779
6780
6781 /*!
6782  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6783  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6784  *
6785  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6786  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6787  *
6788  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6789  * \throw If \a this is not fully defined (coordinates and connectivity)
6790  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6791  */
6792 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6793 {
6794   checkFullyDefined();
6795   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6796   int spaceDim=getSpaceDimension();
6797   mcIdType nbOfCells=getNumberOfCells();
6798   mcIdType nbOfNodes=getNumberOfNodes();
6799   ret->alloc(nbOfCells,spaceDim);
6800   double *ptToFill=ret->getPointer();
6801   const mcIdType *nodal=_nodal_connec->begin();
6802   const mcIdType *nodalI=_nodal_connec_index->begin();
6803   const double *coor=_coords->begin();
6804   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6805     {
6806       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6807       std::fill(ptToFill,ptToFill+spaceDim,0.);
6808       if(type!=INTERP_KERNEL::NORM_POLYHED)
6809         {
6810           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6811             {
6812               if(*conn>=0 && *conn<nbOfNodes)
6813                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6814               else
6815                 {
6816                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6817                   throw INTERP_KERNEL::Exception(oss.str());
6818                 }
6819             }
6820           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6821           if(nbOfNodesInCell>0)
6822             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6823           else
6824             {
6825               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6826               throw INTERP_KERNEL::Exception(oss.str());
6827             }
6828         }
6829       else
6830         {
6831           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6832           s.erase(-1);
6833           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6834             {
6835               if(*it>=0 && *it<nbOfNodes)
6836                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6837               else
6838                 {
6839                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6840                   throw INTERP_KERNEL::Exception(oss.str());
6841                 }
6842             }
6843           if(!s.empty())
6844             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6845           else
6846             {
6847               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6848               throw INTERP_KERNEL::Exception(oss.str());
6849             }
6850         }
6851     }
6852   return ret.retn();
6853 }
6854
6855 /*!
6856  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6857  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6858  * are specified via an array of cell ids.
6859  *  \warning Validity of the specified cell ids is not checked!
6860  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6861  *  \param [in] begin - an array of cell ids of interest.
6862  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6863  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6864  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6865  *          caller is to delete this array using decrRef() as it is no more needed.
6866  *  \throw If the coordinates array is not set.
6867  *  \throw If the nodal connectivity of cells is not defined.
6868  *
6869  *  \if ENABLE_EXAMPLES
6870  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6871  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6872  *  \endif
6873  */
6874 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6875 {
6876   DataArrayDouble *ret=DataArrayDouble::New();
6877   int spaceDim=getSpaceDimension();
6878   std::size_t nbOfTuple=std::distance(begin,end);
6879   ret->alloc(nbOfTuple,spaceDim);
6880   double *ptToFill=ret->getPointer();
6881   double *tmp=new double[spaceDim];
6882   const mcIdType *nodal=_nodal_connec->begin();
6883   const mcIdType *nodalI=_nodal_connec_index->begin();
6884   const double *coor=_coords->begin();
6885   for(const mcIdType *w=begin;w!=end;w++)
6886     {
6887       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6888       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6889       ptToFill+=spaceDim;
6890     }
6891   delete [] tmp;
6892   return ret;
6893 }
6894
6895 /*!
6896  * 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".
6897  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6898  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6899  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6900  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6901  *
6902  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6903  * \throw If spaceDim!=3 or meshDim!=2.
6904  * \throw If connectivity of \a this is invalid.
6905  * \throw If connectivity of a cell in \a this points to an invalid node.
6906  */
6907 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6908 {
6909   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6910   mcIdType nbOfCells=getNumberOfCells();
6911   mcIdType nbOfNodes(getNumberOfNodes());
6912   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6913     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6914   ret->alloc(nbOfCells,4);
6915   double *retPtr(ret->getPointer());
6916   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6917   const double *coor(_coords->begin());
6918   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6919     {
6920       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6921       if(nodalI[1]-nodalI[0]>=4)
6922         {
6923           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6924                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6925                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6926           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6927                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6928                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6929           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]};
6930           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]));
6931           for(int j=0;j<3;j++)
6932             {
6933               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6934               if(nodeId>=0 && nodeId<nbOfNodes)
6935                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6936               else
6937                 {
6938                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6939                   throw INTERP_KERNEL::Exception(oss.str());
6940                 }
6941             }
6942           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6943             {
6944               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6945               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6946             }
6947           else
6948             {
6949               if(nodalI[1]-nodalI[0]==4)
6950                 {
6951                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6952                   throw INTERP_KERNEL::Exception(oss.str());
6953                 }
6954               //
6955               double dd[3]={0.,0.,0.};
6956               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6957                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6958               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6959               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6960               std::copy(dd,dd+3,matrix+4*2);
6961               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6962               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6963             }
6964         }
6965       else
6966         {
6967           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6968           throw INTERP_KERNEL::Exception(oss.str());
6969         }
6970     }
6971   return ret.retn();
6972 }
6973
6974 /*!
6975  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6976  *
6977  */
6978 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6979 {
6980   if(!da)
6981     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6982   da->checkAllocated();
6983   std::string name(da->getName());
6984   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6985   if(name.empty())
6986     ret->setName("Mesh");
6987   ret->setCoords(da);
6988   mcIdType nbOfTuples(da->getNumberOfTuples());
6989   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6990   c->alloc(2*nbOfTuples,1);
6991   cI->alloc(nbOfTuples+1,1);
6992   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6993   *cip++=0;
6994   for(mcIdType i=0;i<nbOfTuples;i++)
6995     {
6996       *cp++=INTERP_KERNEL::NORM_POINT1;
6997       *cp++=i;
6998       *cip++=2*(i+1);
6999     }
7000   ret->setConnectivity(c,cI,true);
7001   return ret.retn();
7002 }
7003
7004 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
7005 {
7006   if(!da)
7007     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
7008   da->checkAllocated();
7009   std::string name(da->getName());
7010   MCAuto<MEDCouplingUMesh> ret;
7011   {
7012     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
7013     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
7014     arr->alloc(da->getNumberOfTuples());
7015     tmp->setCoordsAt(0,arr);
7016     ret=tmp->buildUnstructured();
7017   }
7018   ret->setCoords(da);
7019   if(name.empty())
7020     ret->setName("Mesh");
7021   else
7022     ret->setName(name);
7023   return ret;
7024 }
7025
7026 /*!
7027  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7028  * Cells and nodes of
7029  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7030  *  \param [in] mesh1 - the first mesh.
7031  *  \param [in] mesh2 - the second mesh.
7032  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7033  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7034  *          is no more needed.
7035  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7036  *  \throw If the coordinates array is not set in none of the meshes.
7037  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7038  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7039  */
7040 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7041 {
7042   std::vector<const MEDCouplingUMesh *> tmp(2);
7043   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7044   return MergeUMeshes(tmp);
7045 }
7046
7047 /*!
7048  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7049  * Cells and nodes of
7050  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7051  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7052  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7053  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7054  *          is no more needed.
7055  *  \throw If \a a.size() == 0.
7056  *  \throw If \a a[ *i* ] == NULL.
7057  *  \throw If the coordinates array is not set in none of the meshes.
7058  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7059  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7060  */
7061 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7062 {
7063   std::size_t sz=a.size();
7064   if(sz==0)
7065     return MergeUMeshesLL(a);
7066   for(std::size_t ii=0;ii<sz;ii++)
7067     if(!a[ii])
7068       {
7069         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7070         throw INTERP_KERNEL::Exception(oss.str());
7071       }
7072   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7073   std::vector< const MEDCouplingUMesh * > aa(sz);
7074   int spaceDim=-3;
7075   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7076     {
7077       const MEDCouplingUMesh *cur=a[i];
7078       const DataArrayDouble *coo=cur->getCoords();
7079       if(coo)
7080         spaceDim=int(coo->getNumberOfComponents());
7081     }
7082   if(spaceDim==-3)
7083     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7084   for(std::size_t i=0;i<sz;i++)
7085     {
7086       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7087       aa[i]=bb[i];
7088     }
7089   return MergeUMeshesLL(aa);
7090 }
7091
7092 /*!
7093  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7094  * dimension and sharing the node coordinates array.
7095  * All cells of the first mesh precede all cells of the second mesh
7096  * within the result mesh.
7097  *  \param [in] mesh1 - the first mesh.
7098  *  \param [in] mesh2 - the second mesh.
7099  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7100  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7101  *          is no more needed.
7102  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7103  *  \throw If the meshes do not share the node coordinates array.
7104  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7105  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7106  */
7107 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7108 {
7109   std::vector<const MEDCouplingUMesh *> tmp(2);
7110   tmp[0]=mesh1; tmp[1]=mesh2;
7111   return MergeUMeshesOnSameCoords(tmp);
7112 }
7113
7114 /*!
7115  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7116  * dimension and sharing the node coordinates array.
7117  * All cells of the *i*-th mesh precede all cells of the
7118  * (*i*+1)-th mesh within the result mesh.
7119  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7120  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7121  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7122  *          is no more needed.
7123  *  \throw If \a a.size() == 0.
7124  *  \throw If \a a[ *i* ] == NULL.
7125  *  \throw If the meshes do not share the node coordinates array.
7126  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7127  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7128  */
7129 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7130 {
7131   if(meshes.empty())
7132     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7133   for(std::size_t ii=0;ii<meshes.size();ii++)
7134     if(!meshes[ii])
7135       {
7136         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7137         throw INTERP_KERNEL::Exception(oss.str());
7138       }
7139   const DataArrayDouble *coords=meshes.front()->getCoords();
7140   int meshDim=meshes.front()->getMeshDimension();
7141   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7142   mcIdType meshLgth=0;
7143   mcIdType meshIndexLgth=0;
7144   for(;iter!=meshes.end();iter++)
7145     {
7146       if(coords!=(*iter)->getCoords())
7147         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7148       if(meshDim!=(*iter)->getMeshDimension())
7149         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7150       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7151       meshIndexLgth+=(*iter)->getNumberOfCells();
7152     }
7153   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7154   nodal->alloc(meshLgth,1);
7155   mcIdType *nodalPtr=nodal->getPointer();
7156   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7157   nodalIndex->alloc(meshIndexLgth+1,1);
7158   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7159   mcIdType offset=0;
7160   for(iter=meshes.begin();iter!=meshes.end();iter++)
7161     {
7162       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7163       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7164       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7165       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7166       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7167       if(iter!=meshes.begin())
7168         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7169       else
7170         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7171       offset+=meshLgth2;
7172     }
7173   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7174   ret->setName("merge");
7175   ret->setMeshDimension(meshDim);
7176   ret->setConnectivity(nodal,nodalIndex,true);
7177   ret->setCoords(coords);
7178   return ret;
7179 }
7180
7181 /*!
7182  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7183  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7184  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7185  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7186  * New" mode are returned for each input mesh.
7187  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7188  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7189  *          valid values [0,1,2], see zipConnectivityTraducer().
7190  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7191  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7192  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7193  *          no more needed.
7194  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7195  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7196  *          is no more needed.
7197  *  \throw If \a meshes.size() == 0.
7198  *  \throw If \a meshes[ *i* ] == NULL.
7199  *  \throw If the meshes do not share the node coordinates array.
7200  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7201  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7202  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7203  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7204  */
7205 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7206 {
7207   //All checks are delegated to MergeUMeshesOnSameCoords
7208   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7209   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7210   corr.resize(meshes.size());
7211   std::size_t nbOfMeshes=meshes.size();
7212   mcIdType offset=0;
7213   const mcIdType *o2nPtr=o2n->begin();
7214   for(std::size_t i=0;i<nbOfMeshes;i++)
7215     {
7216       DataArrayIdType *tmp=DataArrayIdType::New();
7217       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7218       tmp->alloc(curNbOfCells,1);
7219       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7220       offset+=curNbOfCells;
7221       tmp->setName(meshes[i]->getName());
7222       corr[i]=tmp;
7223     }
7224   return ret.retn();
7225 }
7226
7227 /*!
7228  * Makes all given meshes share the nodal connectivity array. The common connectivity
7229  * array is created by concatenating the connectivity arrays of all given meshes. All
7230  * the given meshes must be of the same space dimension but dimension of cells **can
7231  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7232  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7233  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7234  *  \param [in,out] meshes - a vector of meshes to update.
7235  *  \throw If any of \a meshes is NULL.
7236  *  \throw If the coordinates array is not set in any of \a meshes.
7237  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7238  *  \throw If \a meshes are of different space dimension.
7239  */
7240 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7241 {
7242   std::size_t sz=meshes.size();
7243   if(sz==0 || sz==1)
7244     return;
7245   std::vector< const DataArrayDouble * > coords(meshes.size());
7246   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7247   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7248     {
7249       if((*it))
7250         {
7251           (*it)->checkConnectivityFullyDefined();
7252           const DataArrayDouble *coo=(*it)->getCoords();
7253           if(coo)
7254             *it2=coo;
7255           else
7256             {
7257               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7258               oss << " has no coordinate array defined !";
7259               throw INTERP_KERNEL::Exception(oss.str());
7260             }
7261         }
7262       else
7263         {
7264           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7265           oss << " is null !";
7266           throw INTERP_KERNEL::Exception(oss.str());
7267         }
7268     }
7269   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7270   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7271   mcIdType offset=(*it)->getNumberOfNodes();
7272   (*it++)->setCoords(res);
7273   for(;it!=meshes.end();it++)
7274     {
7275       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7276       (*it)->setCoords(res);
7277       (*it)->shiftNodeNumbersInConn(offset);
7278       offset+=oldNumberOfNodes;
7279     }
7280 }
7281
7282 /*!
7283  * Merges nodes coincident with a given precision within all given meshes that share
7284  * the nodal connectivity array. The given meshes **can be of different** mesh
7285  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7286  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7287  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7288  *  \param [in,out] meshes - a vector of meshes to update.
7289  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7290  *  \throw If any of \a meshes is NULL.
7291  *  \throw If the \a meshes do not share the same node coordinates array.
7292  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7293  */
7294 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7295 {
7296   if(meshes.empty())
7297     return ;
7298   std::set<const DataArrayDouble *> s;
7299   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7300     {
7301       if(*it)
7302         s.insert((*it)->getCoords());
7303       else
7304         {
7305           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 !";
7306           throw INTERP_KERNEL::Exception(oss.str());
7307         }
7308     }
7309   if(s.size()!=1)
7310     {
7311       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 !";
7312       throw INTERP_KERNEL::Exception(oss.str());
7313     }
7314   const DataArrayDouble *coo=*(s.begin());
7315   if(!coo)
7316     return;
7317   //
7318   DataArrayIdType *comm,*commI;
7319   coo->findCommonTuples(eps,-1,comm,commI);
7320   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7321   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7322   mcIdType newNbOfNodes;
7323   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7324   if(oldNbOfNodes==newNbOfNodes)
7325     return ;
7326   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7327   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7328     {
7329       (*it)->renumberNodesInConn(o2n->begin());
7330       (*it)->setCoords(newCoords);
7331     }
7332 }
7333
7334
7335 /*!
7336  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7337  */
7338 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7339 {
7340   std::size_t i, ip1;
7341   double v[3]={0.,0.,0.};
7342   std::size_t sz=std::distance(begin,end);
7343   if(!isQuadratic)
7344     for(i=0;i<sz;i++)
7345       {
7346         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7347         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7348         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];
7349         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7350         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7351       }
7352   else
7353     {
7354       // Same algorithm as above but also using intermediate quadratic points.
7355       // (taking only linear points might lead to issues if the linearized version of the
7356       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7357       std::size_t hsz = sz/2;
7358       for(std::size_t j=0;j<sz;j++)
7359         {
7360           if (j%2)  // current point i is quadratic, next point i+1 is standard
7361             {
7362               i = hsz+(j-1)/2;
7363               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7364             }
7365           else      // current point i is standard, next point i+1 is quadratic
7366             {
7367               i = j/2;
7368               ip1 = j/2+hsz;
7369             }
7370           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7371           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7372           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7373         }
7374     }
7375   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7376   return (ret>0.);
7377 }
7378
7379 /*!
7380  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7381  */
7382 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7383 {
7384   std::vector<std::pair<mcIdType,mcIdType> > edges;
7385   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7386   const mcIdType *bgFace=begin;
7387   for(std::size_t i=0;i<nbOfFaces;i++)
7388     {
7389       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7390       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7391       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7392         {
7393           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7394           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7395             return false;
7396           edges.push_back(p1);
7397         }
7398       bgFace=endFace+1;
7399     }
7400   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7401 }
7402
7403 /*!
7404  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7405  */
7406 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7407 {
7408   double vec0[3],vec1[3];
7409   std::size_t sz=std::distance(begin,end);
7410   if(sz%2!=0)
7411     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7412   mcIdType nbOfNodes=ToIdType(sz/2);
7413   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7414   const double *pt0=coords+3*begin[0];
7415   const double *pt1=coords+3*begin[nbOfNodes];
7416   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7417   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7418 }
7419
7420 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7421 {
7422   std::size_t sz=std::distance(begin,end);
7423   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7424   std::size_t nbOfNodes(sz/2);
7425   std::copy(begin,end,(mcIdType *)tmp);
7426   for(std::size_t j=1;j<nbOfNodes;j++)
7427     {
7428       begin[j]=tmp[nbOfNodes-j];
7429       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7430     }
7431 }
7432
7433 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7434 {
7435   std::size_t sz=std::distance(begin,end);
7436   if(sz!=4)
7437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7438   double vec0[3],vec1[3];
7439   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7440   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];
7441   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;
7442 }
7443
7444 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7445 {
7446   std::size_t sz=std::distance(begin,end);
7447   if(sz!=5)
7448     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7449   double vec0[3];
7450   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7451   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7452   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7453 }
7454
7455 /*!
7456  * 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 )
7457  * 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
7458  * a 2D space.
7459  *
7460  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7461  * \param [in] coords the coordinates with nb of components exactly equal to 3
7462  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7463  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7464  */
7465 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7466                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7467 {
7468   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7469   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7470   double *vPtr=v->getPointer();
7471   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7472   double *pPtr=p->getPointer();
7473   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7474   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7475   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7476     {
7477       mcIdType face = e_f[e_fi[index] + i];
7478       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7479       // to differentiate faces going to different cells:
7480       pPtr++, *pPtr = 0;
7481       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7482         *pPtr += FromIdType<double>(f_e[j]);
7483     }
7484   pPtr=p->getPointer(); vPtr=v->getPointer();
7485   DataArrayIdType *comm1=0,*commI1=0;
7486   v->findCommonTuples(eps,-1,comm1,commI1);
7487   for (mcIdType i = 0; i < nbFaces; i++)
7488     if (comm1->findIdFirstEqual(i) < 0)
7489       {
7490         comm1->pushBackSilent(i);
7491         commI1->pushBackSilent(comm1->getNumberOfTuples());
7492       }
7493   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7494   const mcIdType *comm1Ptr=comm1->begin();
7495   const mcIdType *commI1Ptr=commI1->begin();
7496   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7497   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7498   //
7499   for(mcIdType i=0;i<nbOfGrps1;i++)
7500     {
7501       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7502       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7503       DataArrayIdType *comm2=0,*commI2=0;
7504       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7505       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7506         if (comm2->findIdFirstEqual(j) < 0)
7507           {
7508             comm2->pushBackSilent(j);
7509             commI2->pushBackSilent(comm2->getNumberOfTuples());
7510           }
7511       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7512       const mcIdType *comm2Ptr=comm2->begin();
7513       const mcIdType *commI2Ptr=commI2->begin();
7514       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7515       for(mcIdType j=0;j<nbOfGrps2;j++)
7516         {
7517           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7518             {
7519               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7520               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7521               res->pushBackSilent(-1);
7522             }
7523           else
7524             {
7525               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7526               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7527               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7528               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7529               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7530               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7531               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7532               const mcIdType *idsNodePtr=idsNode->begin();
7533               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];
7534               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7535               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7536               if(std::abs(norm)>eps)
7537                 {
7538                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7539                   mm3->rotate(center,vec,angle);
7540                 }
7541               mm3->changeSpaceDimension(2);
7542               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7543               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7544               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7545               mcIdType nbOfCells=mm4->getNumberOfCells();
7546               for(mcIdType k=0;k<nbOfCells;k++)
7547                 {
7548                   int l=0;
7549                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7550                     res->pushBackSilent(idsNodePtr[*work]);
7551                   res->pushBackSilent(-1);
7552                 }
7553             }
7554         }
7555     }
7556   res->popBackSilent();
7557 }
7558
7559 /*!
7560  * 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
7561  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7562  *
7563  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7564  * \param [in] coords coordinates expected to have 3 components.
7565  * \param [in] begin start of the nodal connectivity of the face.
7566  * \param [in] end end of the nodal connectivity (excluded) of the face.
7567  * \param [out] v the normalized vector of size 3
7568  * \param [out] p the pos of plane
7569  */
7570 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7571 {
7572   std::size_t nbPoints=std::distance(begin,end);
7573   if(nbPoints<3)
7574     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7575   double vec[3]={0.,0.,0.};
7576   std::size_t j=0;
7577   bool refFound=false;
7578   for(;j<nbPoints-1 && !refFound;j++)
7579     {
7580       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7581       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7582       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7583       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7584       if(norm>eps)
7585         {
7586           refFound=true;
7587           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7588         }
7589     }
7590   for(std::size_t i=j;i<nbPoints-1;i++)
7591     {
7592       double curVec[3];
7593       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7594       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7595       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7596       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7597       if(norm<eps)
7598         continue;
7599       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7600       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];
7601       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7602       if(norm>eps)
7603         {
7604           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7605           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7606           return ;
7607         }
7608     }
7609   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7610 }
7611
7612 /*!
7613  * This method tries to obtain a well oriented polyhedron.
7614  * If the algorithm fails, an exception will be thrown.
7615  */
7616 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7617 {
7618   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7619   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7620   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7621   isPerm[0]=true;
7622   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7623   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7624   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7625   //
7626   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7627     {
7628       bgFace=begin;
7629       std::size_t smthChanged=0;
7630       for(std::size_t i=0;i<nbOfFaces;i++)
7631         {
7632           endFace=std::find(bgFace+1,end,-1);
7633           nbOfEdgesInFace=std::distance(bgFace,endFace);
7634           if(!isPerm[i])
7635             {
7636               bool b=false;
7637               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7638                 {
7639                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7640                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7641                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7642                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7643                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7644                 }
7645               if(isPerm[i])
7646                 {
7647                   if(!b)
7648                     std::reverse(bgFace+1,endFace);
7649                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7650                     {
7651                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7652                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7653                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7654                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7655                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7656                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7657                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7658                       if(it!=edgesOK.end())
7659                         {
7660                           edgesOK.erase(it);
7661                           edgesFinished.push_back(p1);
7662                         }
7663                       else
7664                         edgesOK.push_back(p1);
7665                     }
7666                 }
7667             }
7668           bgFace=endFace+1;
7669         }
7670       if(smthChanged==0)
7671         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7672     }
7673   if(!edgesOK.empty())
7674     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7675   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7676     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7677       bgFace=begin;
7678       for(std::size_t i=0;i<nbOfFaces;i++)
7679         {
7680           endFace=std::find(bgFace+1,end,-1);
7681           std::reverse(bgFace+1,endFace);
7682           bgFace=endFace+1;
7683         }
7684     }
7685 }
7686
7687
7688 /*!
7689  * This method makes the assumption spacedimension == meshdimension == 2.
7690  * This method works only for linear cells.
7691  *
7692  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7693  */
7694 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7695 {
7696   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7697     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7698   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7699   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7700   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7701   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7702   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7703   mcIdType nbCells=skin->getNumberOfCells();
7704   if(nbCells==nbOfNodesExpected)
7705     return buildUnionOf2DMeshLinear(skin,n2o);
7706   else if(2*nbCells==nbOfNodesExpected)
7707     return buildUnionOf2DMeshQuadratic(skin,n2o);
7708   else
7709     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7710 }
7711
7712 /*!
7713  * This method makes the assumption spacedimension == meshdimension == 3.
7714  * This method works only for linear cells.
7715  *
7716  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7717  */
7718 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7719 {
7720   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7721     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7722   MCAuto<MEDCouplingUMesh> m=computeSkin();
7723   const mcIdType *conn=m->getNodalConnectivity()->begin();
7724   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7725   mcIdType nbOfCells=m->getNumberOfCells();
7726   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7727   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7728   if(nbOfCells<1)
7729     return ret.retn();
7730   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7731   for(mcIdType i=1;i<nbOfCells;i++)
7732     {
7733       *work++=-1;
7734       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7735     }
7736   return ret.retn();
7737 }
7738
7739 /*!
7740  * \brief Creates a graph of cell neighbors
7741  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7742  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7743  *  For example
7744  *  - index:  0 3 5 6 6
7745  *  - value:  1 2 3 2 3 3
7746  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7747  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7748  */
7749 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7750 {
7751   checkConnectivityFullyDefined();
7752
7753   int meshDim = this->getMeshDimension();
7754   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7755   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7756   this->getReverseNodalConnectivity(revConn,indexr);
7757   const mcIdType* indexr_ptr=indexr->begin();
7758   const mcIdType* revConn_ptr=revConn->begin();
7759
7760   const MEDCoupling::DataArrayIdType* index;
7761   const MEDCoupling::DataArrayIdType* conn;
7762   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7763   index=this->getNodalConnectivityIndex();
7764   mcIdType nbCells=this->getNumberOfCells();
7765   const mcIdType* index_ptr=index->begin();
7766   const mcIdType* conn_ptr=conn->begin();
7767
7768   //creating graph arcs (cell to cell relations)
7769   //arcs are stored in terms of (index,value) notation
7770   // 0 3 5 6 6
7771   // 1 2 3 2 3 3
7772   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7773   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7774
7775   //warning here one node have less than or equal effective number of cell with it
7776   //but cell could have more than effective nodes
7777   //because other equals nodes in other domain (with other global inode)
7778   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7779   std::vector <mcIdType> cell2cell;
7780   cell2cell.reserve(3*nbCells);
7781
7782   for (mcIdType icell=0; icell<nbCells;icell++)
7783     {
7784       std::map<mcIdType,mcIdType > counter;
7785       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7786         {
7787           mcIdType inode=conn_ptr[iconn];
7788           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7789             {
7790               mcIdType icell2=revConn_ptr[iconnr];
7791               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7792               if (iter!=counter.end()) (iter->second)++;
7793               else counter.insert(std::make_pair(icell2,1));
7794             }
7795         }
7796       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7797            iter!=counter.end(); iter++)
7798         if (iter->second >= meshDim)
7799           {
7800             cell2cell_index[icell+1]++;
7801             cell2cell.push_back(iter->first);
7802           }
7803     }
7804   indexr->decrRef();
7805   revConn->decrRef();
7806   cell2cell_index[0]=0;
7807   for (mcIdType icell=0; icell<nbCells;icell++)
7808     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7809
7810   //filling up index and value to create skylinearray structure
7811   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7812   return array;
7813 }
7814
7815
7816 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7817 {
7818   mcIdType nbOfCells=getNumberOfCells();
7819   if(nbOfCells<=0)
7820     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7821   ofs << "  <" << getVTKDataSetType() << ">\n";
7822   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7823   ofs << "      <PointData>\n" << pointData << std::endl;
7824   ofs << "      </PointData>\n";
7825   ofs << "      <CellData>\n" << cellData << std::endl;
7826   ofs << "      </CellData>\n";
7827   ofs << "      <Points>\n";
7828   if(getSpaceDimension()==3)
7829     _coords->writeVTK(ofs,8,"Points",byteData);
7830   else
7831     {
7832       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7833       coo->writeVTK(ofs,8,"Points",byteData);
7834     }
7835   ofs << "      </Points>\n";
7836   ofs << "      <Cells>\n";
7837   const mcIdType *cPtr=_nodal_connec->begin();
7838   const mcIdType *cIPtr=_nodal_connec_index->begin();
7839   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7840   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7841   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7842   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7843   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7844   mcIdType szFaceOffsets=0,szConn=0;
7845   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7846     {
7847       *w2=cPtr[cIPtr[i]];
7848       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7849         {
7850           *w1=-1;
7851           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7852           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7853         }
7854       else
7855         {
7856           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7857           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7858           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7859           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7860           w4=std::copy(c.begin(),c.end(),w4);
7861         }
7862     }
7863   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7864   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7865     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7866   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7867   types->writeVTK(ofs,8,"UInt8","types",byteData);
7868   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7869   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7870   if(szFaceOffsets!=0)
7871     {//presence of Polyhedra
7872       connectivity->reAlloc(szConn);
7873       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7874       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7875       w1=faces->getPointer();
7876       for(mcIdType i=0;i<nbOfCells;i++)
7877         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7878           {
7879             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7880             *w1++=nbFaces;
7881             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7882             for(mcIdType j=0;j<nbFaces;j++)
7883               {
7884                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7885                 *w1++=ToIdType(std::distance(w6,w5));
7886                 w1=std::copy(w6,w5,w1);
7887                 w6=w5+1;
7888               }
7889           }
7890       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7891     }
7892   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7893   ofs << "      </Cells>\n";
7894   ofs << "    </Piece>\n";
7895   ofs << "  </" << getVTKDataSetType() << ">\n";
7896 }
7897
7898 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7899 {
7900   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7901   if(_mesh_dim==-2)
7902     { stream << " Not set !"; return ; }
7903   stream << " Mesh dimension : " << _mesh_dim << ".";
7904   if(_mesh_dim==-1)
7905     return ;
7906   if(!_coords)
7907     { stream << " No coordinates set !"; return ; }
7908   if(!_coords->isAllocated())
7909     { stream << " Coordinates set but not allocated !"; return ; }
7910   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7911   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7912   if(!_nodal_connec_index)
7913     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7914   if(!_nodal_connec_index->isAllocated())
7915     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7916   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7917   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7918   if(cpt!=1 || lgth<1)
7919     return ;
7920   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7921 }
7922
7923 std::string MEDCouplingUMesh::getVTKDataSetType() const
7924 {
7925   return std::string("UnstructuredGrid");
7926 }
7927
7928 std::string MEDCouplingUMesh::getVTKFileExtension() const
7929 {
7930   return std::string("vtu");
7931 }
7932
7933
7934
7935 /**
7936  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7937  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7938  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7939  * The caller is to deal with the resulting DataArrayIdType.
7940  *  \throw If the coordinate array is not set.
7941  *  \throw If the nodal connectivity of the cells is not defined.
7942  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7943  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7944  *
7945  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7946  */
7947 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7948 {
7949   checkFullyDefined();
7950   if(getMeshDimension()!=1)
7951     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7952
7953   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7954   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7955   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7956   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7957   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7958   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7959   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7960   const mcIdType * dsi(_dsi->begin());
7961   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7962   m_points=0;
7963   if (dsii->getNumberOfTuples())
7964     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7965
7966   mcIdType nc=getNumberOfCells();
7967   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7968   result->alloc(nc,1);
7969
7970   // set of edges not used so far
7971   std::set<mcIdType> edgeSet;
7972   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7973
7974   mcIdType startSeg=0;
7975   mcIdType newIdx=0;
7976   // while we have points with only one neighbor segments
7977   do
7978     {
7979       std::list<mcIdType> linePiece;
7980       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7981       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7982         {
7983           // Fill the list forward (resp. backward) from the start segment:
7984           mcIdType activeSeg = startSeg;
7985           mcIdType prevPointId = -20;
7986           mcIdType ptId;
7987           while (!edgeSet.empty())
7988             {
7989               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7990                 {
7991                   if (direction==0)
7992                     linePiece.push_back(activeSeg);
7993                   else
7994                     linePiece.push_front(activeSeg);
7995                   edgeSet.erase(activeSeg);
7996                 }
7997
7998               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7999               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
8000               if (dsi[ptId] == 1) // hitting the end of the line
8001                 break;
8002
8003               prevPointId = ptId;
8004               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
8005               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
8006
8007               //for piecewise meshes made up of closed parts
8008               bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
8009               if(segmentAlreadyTreated)
8010                 break;
8011             }
8012         }
8013       // Done, save final piece into DA:
8014       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
8015       newIdx += ToIdType(linePiece.size());
8016
8017       // identify next valid start segment (one which is not consumed)
8018       if(!edgeSet.empty())
8019         startSeg = *(edgeSet.begin());
8020
8021     }
8022   while (!edgeSet.empty());
8023   return result.retn();
8024 }
8025
8026 /**
8027  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
8028  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
8029  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
8030  * a minimal creation of new nodes is wanted.
8031  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
8032  * nodes if a SEG3 is split without information of middle.
8033  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
8034  * avoid to have a non conform mesh.
8035  *
8036  * \return mcIdType - the number of new nodes created (in most of cases 0).
8037  *
8038  * \throw If \a this is not coherent.
8039  * \throw If \a this has not spaceDim equal to 2.
8040  * \throw If \a this has not meshDim equal to 2.
8041  * \throw If some subcells needed to be split are orphan.
8042  * \sa MEDCouplingUMesh::conformize2D
8043  */
8044 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8045 {
8046   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8047     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8048   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8049   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8050     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8051   if(midOpt==0 && midOptI==0)
8052     {
8053       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8054       return 0;
8055     }
8056   else if(midOpt!=0 && midOptI!=0)
8057     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8058   else
8059     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8060 }
8061
8062 /*!
8063  * 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
8064  * 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
8065  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8066  * 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
8067  * 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.
8068  *
8069  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8070  */
8071 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8072 {
8073   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8074   if(sz>=4)
8075     {
8076       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8077       if(cm.getDimension()==2)
8078         {
8079           const mcIdType *node=nodalConnBg+1;
8080           mcIdType startNode=*node++;
8081           double refX=coords[2*startNode];
8082           for(;node!=nodalConnEnd;node++)
8083             {
8084               if(coords[2*(*node)]<refX)
8085                 {
8086                   startNode=*node;
8087                   refX=coords[2*startNode];
8088                 }
8089             }
8090           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8091           refX=1e300;
8092           double tmp1;
8093           double tmp2[2];
8094           double angle0=-M_PI/2;
8095           //
8096           mcIdType nextNode=-1;
8097           mcIdType prevNode=-1;
8098           double resRef;
8099           double angleNext=0.;
8100           while(nextNode!=startNode)
8101             {
8102               nextNode=-1;
8103               resRef=1e300;
8104               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8105                 {
8106                   if(*node!=tmpOut.back() && *node!=prevNode)
8107                     {
8108                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8109                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8110                       double res;
8111                       if(angleM<=angle0)
8112                         res=angle0-angleM;
8113                       else
8114                         res=angle0-angleM+2.*M_PI;
8115                       if(res<resRef)
8116                         {
8117                           nextNode=*node;
8118                           resRef=res;
8119                           angleNext=angleM;
8120                         }
8121                     }
8122                 }
8123               if(nextNode!=startNode)
8124                 {
8125                   angle0=angleNext-M_PI;
8126                   if(angle0<-M_PI)
8127                     angle0+=2*M_PI;
8128                   prevNode=tmpOut.back();
8129                   tmpOut.push_back(nextNode);
8130                 }
8131             }
8132           std::vector<mcIdType> tmp3(2*(sz-1));
8133           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8134           std::copy(nodalConnBg+1,nodalConnEnd,it);
8135           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8136             {
8137               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8138               return false;
8139             }
8140           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8141             {
8142               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8143               return false;
8144             }
8145           else
8146             {
8147               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8148               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8149               return true;
8150             }
8151         }
8152       else
8153         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8154     }
8155   else
8156     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8157 }
8158
8159 /*!
8160  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8161  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8162  * 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]].
8163  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8164  * A negative value in \b arrIn means that it is ignored.
8165  * 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.
8166  *
8167  * \param [in] arrIn arr origin array from which the extraction will be done.
8168  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8169  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8170  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8171  */
8172 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8173 {
8174   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8175   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8176 }
8177
8178 /*!
8179  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8180  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8181  * 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]].
8182  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8183  * A negative value in \b arrIn means that it is ignored.
8184  * 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.
8185  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8186  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8187  * \param [in] arrIn arr origin array from which the extraction will be done.
8188  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8189  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8190  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8191  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8192  * \sa MEDCouplingUMesh::partitionBySpreadZone
8193  */
8194 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8195 {
8196   nbOfDepthPeelingPerformed=0;
8197   if(!arrIndxIn)
8198     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8199   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8200   if(nbOfTuples<=0)
8201     {
8202       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8203       return ret;
8204     }
8205   //
8206   std::vector<bool> fetched(nbOfTuples,false);
8207   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8208 }
8209
8210
8211
8212 /*!
8213  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8214  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8215  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8216  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8217  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8218  *
8219  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8220  */
8221 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8222 {
8223   checkFullyDefined();
8224   int mdim=getMeshDimension();
8225   int spaceDim=getSpaceDimension();
8226   if(mdim!=spaceDim)
8227     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8228   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8229   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8230   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8231   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8232   ret->setCoords(getCoords());
8233   ret->allocateCells(ToIdType(partition.size()));
8234   //
8235   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8236     {
8237       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8238       MCAuto<DataArrayIdType> cell;
8239       switch(mdim)
8240       {
8241         case 2:
8242           cell=tmp->buildUnionOf2DMesh();
8243           break;
8244         case 3:
8245           cell=tmp->buildUnionOf3DMesh();
8246           break;
8247         default:
8248           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8249       }
8250
8251       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8252     }
8253   //
8254   ret->finishInsertingCells();
8255   return ret.retn();
8256 }
8257
8258 /*!
8259  * This method partitions \b this into contiguous zone.
8260  * This method only needs a well defined connectivity. Coordinates are not considered here.
8261  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8262  */
8263 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8264 {
8265   DataArrayIdType *neigh=0,*neighI=0;
8266   computeNeighborsOfCells(neigh,neighI);
8267   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8268   return PartitionBySpreadZone(neighAuto,neighIAuto);
8269 }
8270
8271 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8272 {
8273   if(!arrIn || !arrIndxIn)
8274     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8275   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8276   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8277   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8278     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8279   mcIdType nbOfCellsCur(nbOfTuples-1);
8280   std::vector<DataArrayIdType *> ret;
8281   if(nbOfCellsCur<=0)
8282     return ret;
8283   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8284   std::vector< MCAuto<DataArrayIdType> > ret2;
8285   mcIdType seed=0;
8286   while(seed<nbOfCellsCur)
8287     {
8288       mcIdType nbOfPeelPerformed=0;
8289       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8290       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8291     }
8292   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8293     ret.push_back((*it).retn());
8294   return ret;
8295 }
8296
8297 /*!
8298  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8299  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8300  *
8301  * \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.
8302  * \return a newly allocated DataArrayIdType to be managed by the caller.
8303  * \throw In case of \a code has not the right format (typically of size 3*n)
8304  */
8305 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8306 {
8307   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8308   std::size_t nb=code.size()/3;
8309   if(code.size()%3!=0)
8310     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8311   ret->alloc(nb,2);
8312   mcIdType *retPtr=ret->getPointer();
8313   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8314     {
8315       retPtr[0]=code[3*i+2];
8316       retPtr[1]=code[3*i+2]+code[3*i+1];
8317     }
8318   return ret.retn();
8319 }
8320
8321 /*!
8322  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8323  * All cells in \a this are expected to be linear 3D cells.
8324  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8325  * It leads to an increase to number of cells.
8326  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8327  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8328  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8329  *
8330  * \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.
8331  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8332  * \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.
8333  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8334  *          an id of old cell producing it. The caller is to delete this array using
8335  *         decrRef() as it is no more needed.
8336  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8337  *
8338  * \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
8339  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8340  *
8341  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8342  * \throw If \a this is not fully constituted with linear 3D cells.
8343  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8344  */
8345 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8346 {
8347   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8348   checkConnectivityFullyDefined();
8349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8351   mcIdType nbOfCells=getNumberOfCells();
8352   mcIdType nbNodes(getNumberOfNodes());
8353   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8354   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8355   mcIdType *retPt(ret->getPointer());
8356   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8357   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8358   const mcIdType *oldc(_nodal_connec->begin());
8359   const mcIdType *oldci(_nodal_connec_index->begin());
8360   const double *coords(_coords->begin());
8361   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8362     {
8363       std::vector<mcIdType> a; std::vector<double> b;
8364       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8365       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8366       const mcIdType *aa(&a[0]);
8367       if(!b.empty())
8368         {
8369           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8370             if(*it<0)
8371               *it=(-(*(it))-1+nbNodes);
8372           addPts->insertAtTheEnd(b.begin(),b.end());
8373           nbNodes+=ToIdType(b.size()/3);
8374         }
8375       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8376         newConn->insertAtTheEnd(aa,aa+4);
8377     }
8378   if(!addPts->empty())
8379     {
8380       addPts->rearrange(3);
8381       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8382       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8383       ret0->setCoords(addPts);
8384     }
8385   else
8386     {
8387       nbOfAdditionalPoints=0;
8388       ret0->setCoords(getCoords());
8389     }
8390   ret0->setNodalConnectivity(newConn);
8391   //
8392   ret->computeOffsetsFull();
8393   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8394   return ret0.retn();
8395 }
8396
8397 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8398     _own_cell(true),_cell_id(-1),_nb_cell(0)
8399 {
8400   if(mesh)
8401     {
8402       mesh->incrRef();
8403       _nb_cell=mesh->getNumberOfCells();
8404     }
8405 }
8406
8407 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8408 {
8409   if(_mesh)
8410     _mesh->decrRef();
8411   if(_own_cell)
8412     delete _cell;
8413 }
8414
8415 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8416     _own_cell(false),_cell_id(bg-1),
8417     _nb_cell(end)
8418 {
8419   if(mesh)
8420     mesh->incrRef();
8421 }
8422
8423 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8424 {
8425   _cell_id++;
8426   if(_cell_id<_nb_cell)
8427     {
8428       _cell->next();
8429       return _cell;
8430     }
8431   else
8432     return 0;
8433 }
8434
8435 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8436 {
8437   if(_mesh)
8438     _mesh->incrRef();
8439 }
8440
8441 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8442 {
8443   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8444 }
8445
8446 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8447 {
8448   if(_mesh)
8449     _mesh->decrRef();
8450 }
8451
8452 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8453     _itc(itc),
8454     _bg(bg),_end(end)
8455 {
8456   if(_mesh)
8457     _mesh->incrRef();
8458 }
8459
8460 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8461 {
8462   if(_mesh)
8463     _mesh->decrRef();
8464 }
8465
8466 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8467 {
8468   return _type;
8469 }
8470
8471 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8472 {
8473   return _end-_bg;
8474 }
8475
8476 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8477 {
8478   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8479 }
8480
8481 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8482 {
8483   if(mesh)
8484     {
8485       mesh->incrRef();
8486       _nb_cell=mesh->getNumberOfCells();
8487     }
8488 }
8489
8490 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8491 {
8492   if(_mesh)
8493     _mesh->decrRef();
8494   delete _cell;
8495 }
8496
8497 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8498 {
8499   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8500   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8501   if(_cell_id<_nb_cell)
8502     {
8503       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8504       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8505       mcIdType startId=_cell_id;
8506       _cell_id+=nbOfElems;
8507       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8508     }
8509   else
8510     return 0;
8511 }
8512
8513 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8514 {
8515   if(mesh)
8516     {
8517       _conn=mesh->getNodalConnectivity()->getPointer();
8518       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8519     }
8520 }
8521
8522 void MEDCouplingUMeshCell::next()
8523 {
8524   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8525     {
8526       _conn+=_conn_lgth;
8527       _conn_indx++;
8528     }
8529   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8530 }
8531
8532 std::string MEDCouplingUMeshCell::repr() const
8533 {
8534   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8535     {
8536       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8537       oss << " : ";
8538       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8539       return oss.str();
8540     }
8541   else
8542     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8543 }
8544
8545 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8546 {
8547   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8548     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8549   else
8550     return INTERP_KERNEL::NORM_ERROR;
8551 }
8552
8553 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8554 {
8555   lgth=_conn_lgth;
8556   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8557     return _conn;
8558   else
8559     return 0;
8560 }
8561
8562 /// @cond INTERNAL
8563
8564 namespace MEDCouplingImpl
8565 {
8566   const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8567
8568   //================================================================================
8569   /*!
8570    * \brief Encode a cell id and a mesh index into a code
8571    *  \param [in] id - cell id
8572    *  \param [in] iMesh - mesh index [0,1]
8573    *  \return mcIdType - code
8574    */
8575   //================================================================================
8576
8577   mcIdType encodeID( mcIdType id, int iMesh )
8578   {
8579     return ( id + 1 ) * ( iMesh ? -1 : 1 );
8580   }
8581   //================================================================================
8582   /*!
8583    * \brief Return cell id and mesh index by a given id
8584    *  \param [in] id - code of a cell in a mesh
8585    *  \param [out] iMesh - returned mesh index
8586    *  \return mcIdType - cell id
8587    */
8588   //================================================================================
8589
8590   mcIdType decodeID( mcIdType id, int& iMesh )
8591   {
8592     iMesh = ( id < 0 );
8593     return std::abs( id ) - 1;
8594   }
8595
8596   //================================================================================
8597   /*!
8598    * \brief return another face sharing two given nodes of a face edge
8599    *  \param [in] n0 - 1st node of the edge
8600    *  \param [in] n1 - 2nd node of the edge
8601    *  \param [in] inputFaceID - face including \a n0 andf \a n2
8602    *  \param [in] mesh - object and reference meshes
8603    *  \param [in] revNodal - reverse nodal connectivity of the two meshes
8604    *  \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8605    *  \param [out] facesByEdge - return another face including \a n0 andf \a n2
8606    *  \param [out] equalFaces - return faces equal to facesByEdge
8607    */
8608   //================================================================================
8609
8610   void getFacesOfEdge( mcIdType n0,
8611                        mcIdType n1,
8612                        mcIdType inputFaceID,
8613                        MEDCouplingUMesh* mesh[],
8614                        MCAuto<DataArrayIdType> revNodal[],
8615                        MCAuto<DataArrayIdType> revNodalIndx[],
8616                        std::vector< mcIdType >& facesByEdge,
8617                        std::vector< mcIdType >& equalFaces)
8618   {
8619     // find faces sharing the both nodes of edge
8620
8621     facesByEdge.clear();
8622     size_t prevNbF; // nb faces found in 0-th mesh
8623     for ( int iM = 0; iM < 2; ++iM )
8624       {
8625         const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8626         const mcIdType * rev    = revNodal    [ iM ]->begin();
8627
8628         mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8629         mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8630
8631         prevNbF = facesByEdge.size();
8632         facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8633
8634         auto it = std::set_intersection( rev + revInd[ n0 ],
8635                                          rev + revInd[ n0 ] + nbRevFaces0,
8636                                          rev + revInd[ n1 ],
8637                                          rev + revInd[ n1 ] + nbRevFaces1,
8638                                          facesByEdge.begin() + prevNbF );
8639         facesByEdge.resize( it - facesByEdge.begin() );
8640       }
8641
8642     // facesByEdge now contains at least the 'inputFaceID'
8643     // check if there are other faces
8644
8645     size_t nbF = facesByEdge.size();
8646     if ( nbF > 1 )
8647       {
8648         if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8649           {
8650             // remove from facesByEdge equal faces in different meshes
8651             const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8652                                          mesh[1]->getNodalConnectivity()->getConstPointer() };
8653             const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8654                                          mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8655             for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8656               {
8657                 if ( facesByEdge[ i0 ] == theUndefID )
8658                   continue;
8659                 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8660                 bool   isInputFace = ( objFaceID == inputFaceID );
8661
8662                 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8663                   {
8664                     if ( facesByEdge[ i1 ] == theUndefID )
8665                       continue;
8666
8667                     mcIdType f0 = facesByEdge[ i0 ];
8668                     mcIdType f1 = facesByEdge[ i1 ];
8669                     size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8670                     size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8671                     if ( nbNodes0 != nbNodes1 )
8672                       continue;
8673
8674                     const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8675                     const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8676                     if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8677                       {
8678                         // equal faces; remove an object one
8679                         mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8680                         if ( refFaceID == inputFaceID )
8681                           isInputFace = true;
8682
8683                         if ( std::find( equalFaces.begin(),
8684                                         equalFaces.end(), objFaceID ) == equalFaces.end() )
8685                           equalFaces.push_back( objFaceID );
8686
8687                         facesByEdge[ i0 ] = theUndefID;
8688                         if ( isInputFace )
8689                           facesByEdge[ i1 ] = theUndefID;
8690                         break;
8691                       }
8692                   }
8693                 if ( isInputFace )
8694                   facesByEdge[ i0 ] = theUndefID;
8695               }
8696           }
8697       }
8698
8699     nbF = facesByEdge.size();
8700     for ( size_t i = 0; i < facesByEdge.size(); ++i )
8701       {
8702         if ( facesByEdge[ i ] != theUndefID )
8703           {
8704             facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8705             if ( facesByEdge[ i ] == inputFaceID )
8706               facesByEdge[ i ] = theUndefID;
8707           }
8708         nbF -= ( facesByEdge[ i ] == theUndefID );
8709       }
8710
8711     if ( nbF > 1 )
8712       return; // non-manifold
8713
8714     if ( nbF < 1 )
8715       {
8716         facesByEdge.clear();
8717       }
8718     else // nbF == 1, set a found face first
8719       {
8720         if ( facesByEdge[ 0 ] == theUndefID )
8721           {
8722             for ( size_t i = 1; i < facesByEdge.size(); ++i )
8723               if ( facesByEdge[ i ] != theUndefID )
8724                 {
8725                   facesByEdge[ 0 ] = facesByEdge[ i ];
8726                   break;
8727                 }
8728           }
8729         facesByEdge.resize( 1 );
8730       }
8731     return;
8732   }
8733
8734   //================================================================================
8735   /*!
8736    * \brief Remove a face from nodal reversed connectivity
8737    *  \param [in] node - a node of the face
8738    *  \param [in] face - the face
8739    *  \param [in.out] revNodal - reverse nodal connectivity
8740    *  \param [in,out] revNodalIndx - reverse nodal connectivity index
8741    */
8742   //================================================================================
8743
8744   void removeFromRevNodal( mcIdType node,
8745                            mcIdType face,
8746                            MCAuto<DataArrayIdType>& revNodal,
8747                            MCAuto<DataArrayIdType>& revNodalIndx)
8748   {
8749     mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8750     mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8751     auto it = std::find( fBeg, fEnd, face );
8752     if ( it != fEnd )
8753       {
8754         for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8755           *( it2 - 1 ) = *it2;
8756
8757         *( fEnd - 1 ) = theUndefID;
8758       }
8759   }
8760
8761   //================================================================================
8762   /*!
8763    * \brief Check order of two nodes in a given face
8764    *  \param [inout] n0 - node 1
8765    *  \param [inout] n1 - node 2
8766    *  \param [inout] iFEnc - face
8767    *  \param [inout] mesh - mesh
8768    *  \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8769    */
8770   //================================================================================
8771
8772   bool isReverseOrder( mcIdType n0,
8773                        mcIdType n1,
8774                        mcIdType iFEnc,
8775                        MEDCouplingUMesh* mesh[] )
8776   {
8777     int iMesh;
8778     mcIdType iF = decodeID( iFEnc, iMesh );
8779
8780     const mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8781     const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8782
8783     auto it0 = std::find( conn + connI[ iF ] + 1,
8784                           conn + connI[ iF + 1 ],
8785                           n0 );
8786     auto it1 = std::find( conn + connI[ iF ] + 1,
8787                           conn + connI[ iF + 1 ],
8788                           n1 );
8789     long i0 = it0 - conn;
8790     long i1 = it1 - conn;
8791
8792     bool isRev = ( std::abs( i1 - i0 ) == 1 ) ?  i1 < i0 :  i0 < i1;
8793     return isRev;
8794   }
8795
8796   //================================================================================
8797   /*!
8798    * \brief Change orientation of a face in one of given meshes
8799    *  \param [in] iFEnc - face ID also encoding a mesh index
8800    *  \param [in,out] mesh - object and reference meshes
8801    */
8802   //================================================================================
8803
8804   void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8805   {
8806     int iMesh;
8807     mcIdType face = decodeID( iFEnc, iMesh );
8808
8809     mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8810     mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8811
8812     const INTERP_KERNEL::CellModel& cm =
8813       INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8814
8815     cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8816                               (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8817     return;
8818   }
8819 }
8820
8821 /// @endcond
8822
8823 //================================================================================
8824 /*!
8825  * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8826  *  \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8827  *              If there are no cells in \a refFaces or it is nullptr, then any face
8828  *              in \a this mesh is used as a reference
8829  *  \throw If \a this mesh is not well defined.
8830  *  \throw If \a this mesh or \refFaces are not 2D.
8831  *  \throw If \a this mesh and \refFaces do not share nodes.
8832  *  \throw If \a refFaces are not equally oriented.
8833  *  \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8834  *
8835  *  \if ENABLE_EXAMPLES
8836  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8837  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8838  *  \endif
8839  */
8840 //================================================================================
8841
8842 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8843 {
8844   checkConsistencyLight();
8845   if ( getMeshDimension() != 2 )
8846     throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8847   if ( refFaces )
8848     {
8849       refFaces->checkConsistencyLight();
8850       if ( refFaces->getMeshDimension() != 2 )
8851         throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8852       if ( getCoords() != refFaces->getCoords() )
8853         throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8854       if ( refFaces->getNumberOfCells() == 0 )
8855         refFaces = nullptr;
8856     }
8857   if ( getNumberOfCells() == 0 )
8858     return;
8859
8860   enum { _OBJ, _REF };
8861   MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8862   MCAuto<MEDCouplingUMesh> meshPtr;
8863   if ( !mesh[_REF] )
8864     {
8865       meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8866       mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8867       mesh[_REF]->allocateCells(0);
8868       mesh[_REF]->finishInsertingCells();
8869     }
8870   mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8871                                  mesh[_REF]->getNumberOfCells() };
8872   std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8873   isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8874   isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8875
8876   MCAuto<DataArrayIdType> revNodal    [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8877   MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8878   mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8879   mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8880
8881   std::vector< mcIdType > faceNodes(4);
8882   std::vector< mcIdType > facesByEdge(4), equalFaces;
8883   std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8884
8885   while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8886     {
8887       if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8888         {
8889           for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8890             if ( nbFacesToCheck[iMesh] > 0 )
8891               for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8892                 if ( !isFaceQueued[iMesh][f] )
8893                   {
8894                     faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8895                     isFaceQueued[ iMesh ][ f ] = true;
8896                     iMesh = 0;
8897                     break;
8898                   }
8899           if ( faceQueue.empty() )
8900             break;
8901         }
8902
8903       mcIdType fID = faceQueue.back();
8904       faceQueue.pop_back();
8905
8906       int iMesh, iMesh2;
8907       mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8908
8909       nbFacesToCheck[iMesh]--;
8910
8911       equalFaces.clear();
8912       faceNodes.clear();
8913       mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8914       const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8915       const int nbEdges = cm.getNumberOfSons();
8916
8917       // loop on edges of the refFace
8918       mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8919       for ( int edge = 0; edge < nbEdges; ++edge )
8920         {
8921           mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8922
8923           // get faces sharing the edge
8924           MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8925                                            facesByEdge, equalFaces );
8926
8927           if ( facesByEdge.size() > 1 )
8928             THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8929
8930           if ( facesByEdge.size() == 1 )
8931             {
8932               // compare orientation of two faces
8933               //
8934               if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8935                 {
8936                   if ( facesByEdge[0] < 0 ) // in the ref mesh
8937                     throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8938
8939                   MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8940                 }
8941               mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8942               if ( !isFaceQueued[iMesh2][face2] )
8943                 {
8944                   isFaceQueued[iMesh2][face2] = true;
8945                   faceQueue.push_back( facesByEdge[0] );
8946                 }
8947             }
8948           n0 = n1;
8949         }
8950
8951       // remove face and equalFaces from revNodal in order not to treat them again
8952       equalFaces.push_back( fID );
8953       for ( mcIdType face : equalFaces )
8954         {
8955           mcIdType f            = MEDCouplingImpl::decodeID( face, iMesh2 );
8956           const mcIdType *conn  = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8957           const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8958           mcIdType nbNodes      = connI[ f + 1 ] - connI[ f ] - 1;
8959           for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8960
8961             MEDCouplingImpl::removeFromRevNodal( *n, f,  // not to treat f again
8962                                                  revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8963         }
8964
8965     } // while() until all faces checked
8966
8967   return;
8968 }