Salome HOME
3f885cd438f42416d740936f6ae51fac29acd3b8
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1344  *             precision.
1345  */
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1347 {
1348   checkFullyDefined();
1349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352   coords->recenterForMaxPrecision(eps);
1353   //
1354   mcIdType nbOfCells=getNumberOfCells();
1355   const mcIdType *conn=_nodal_connec->getConstPointer();
1356   const mcIdType *index=_nodal_connec_index->getConstPointer();
1357   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358   connINew->alloc(nbOfCells+1,1);
1359   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1363   bool changed=false;
1364   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1365     {
1366       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1367         {
1368           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1369           changed=true;
1370         }
1371       else
1372         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373       *connINewPtr=connNew->getNumberOfTuples();
1374     }
1375   if(changed)
1376     setConnectivity(connNew,connINew,false);
1377 }
1378
1379 /*!
1380  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382  * the format of the returned DataArrayIdType instance.
1383  *
1384  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1386  */
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1388 {
1389   checkConnectivityFullyDefined();
1390   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392   std::vector<bool> retS(maxElt,false);
1393   computeNodeIdsAlg(retS);
1394   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1395 }
1396
1397 /*!
1398  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1400  */
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1402 {
1403   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404            nbOfCells=getNumberOfCells();
1405   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406   for(mcIdType i=0;i<nbOfCells;i++)
1407     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1408       if(conn[j]>=0)
1409         {
1410           if(conn[j]<nbOfNodes)
1411             nodeIdsInUse[conn[j]]=true;
1412           else
1413             {
1414               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1415               throw INTERP_KERNEL::Exception(oss.str());
1416             }
1417         }
1418 }
1419
1420 /// @cond INTERNAL
1421
1422 struct MEDCouplingAccVisit
1423 {
1424   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426   mcIdType _new_nb_of_nodes;
1427 };
1428
1429 /// @endcond
1430
1431 /*!
1432  * Finds nodes not used in any cell and returns an array giving a new id to every node
1433  * by excluding the unused nodes, for which the array holds -1. The result array is
1434  * a mapping in "Old to New" mode.
1435  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438  *          if the node is unused or a new id else. The caller is to delete this
1439  *          array using decrRef() as it is no more needed.
1440  *  \throw If the coordinates array is not set.
1441  *  \throw If the nodal connectivity of cells is not defined.
1442  *  \throw If the nodal connectivity includes an invalid id.
1443  *
1444  *  \if ENABLE_EXAMPLES
1445  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1447  *  \endif
1448  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1449  */
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1451 {
1452   nbrOfNodesInUse=-1;
1453   mcIdType nbOfNodes(getNumberOfNodes());
1454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455   ret->alloc(nbOfNodes,1);
1456   mcIdType *traducer=ret->getPointer();
1457   std::fill(traducer,traducer+nbOfNodes,-1);
1458   mcIdType nbOfCells=getNumberOfCells();
1459   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460   const mcIdType *conn=_nodal_connec->getConstPointer();
1461   for(mcIdType i=0;i<nbOfCells;i++)
1462     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1463       if(conn[j]>=0)
1464         {
1465           if(conn[j]<nbOfNodes)
1466             traducer[conn[j]]=1;
1467           else
1468             {
1469               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1470               throw INTERP_KERNEL::Exception(oss.str());
1471             }
1472         }
1473   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1475   return ret.retn();
1476 }
1477
1478 /*!
1479  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480  * For each cell in \b this the number of nodes constituting cell is computed.
1481  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482  * So for pohyhedrons some nodes can be counted several times in the returned result.
1483  *
1484  * \return a newly allocated array
1485  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1486  */
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1488 {
1489   checkConnectivityFullyDefined();
1490   mcIdType nbOfCells=getNumberOfCells();
1491   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492   ret->alloc(nbOfCells,1);
1493   mcIdType *retPtr=ret->getPointer();
1494   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1497     {
1498       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499         *retPtr=connI[i+1]-connI[i]-1;
1500       else
1501         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1502     }
1503   return ret.retn();
1504 }
1505
1506 /*!
1507  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1509  *
1510  * \return DataArrayIdType * - new object to be deallocated by the caller.
1511  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1512  */
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1514 {
1515   checkConnectivityFullyDefined();
1516   mcIdType nbOfCells=getNumberOfCells();
1517   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518   ret->alloc(nbOfCells,1);
1519   mcIdType *retPtr=ret->getPointer();
1520   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1523     {
1524       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526         *retPtr=ToIdType(s.size());
1527       else
1528         {
1529           s.erase(-1);
1530           *retPtr=ToIdType(s.size());
1531         }
1532     }
1533   return ret.retn();
1534 }
1535
1536 /*!
1537  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1539  *
1540  * \return a newly allocated array
1541  */
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1543 {
1544   checkConnectivityFullyDefined();
1545   mcIdType nbOfCells=getNumberOfCells();
1546   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547   ret->alloc(nbOfCells,1);
1548   mcIdType *retPtr=ret->getPointer();
1549   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1552     {
1553       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1555     }
1556   return ret.retn();
1557 }
1558
1559 /*!
1560  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562  * array mean that the corresponding old node is no more used.
1563  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564  *           this->getNumberOfNodes() before call of this method. The caller is to
1565  *           delete this array using decrRef() as it is no more needed.
1566  *  \throw If the coordinates array is not set.
1567  *  \throw If the nodal connectivity of cells is not defined.
1568  *  \throw If the nodal connectivity includes an invalid id.
1569  *  \sa areAllNodesFetched
1570  *
1571  *  \if ENABLE_EXAMPLES
1572  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1574  *  \endif
1575  */
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1577 {
1578   return MEDCouplingPointSet::zipCoordsTraducer();
1579 }
1580
1581 /*!
1582  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1584  */
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1586 {
1587   switch(compType)
1588   {
1589     case 0:
1590       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1591     case 1:
1592       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1593     case 2:
1594       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1595     case 3:
1596       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1597     case 7:
1598       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1599   }
1600   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1610   return 0;
1611 }
1612
1613 /*!
1614  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1615  */
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1617 {
1618   mcIdType sz=connI[cell1+1]-connI[cell1];
1619   if(sz==connI[cell2+1]-connI[cell2])
1620     {
1621       if(conn[connI[cell1]]==conn[connI[cell2]])
1622         {
1623           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624           unsigned dim=cm.getDimension();
1625           if(dim!=3)
1626             {
1627               if(dim!=1)
1628                 {
1629                   mcIdType sz1=2*(sz-1);
1630                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634                   return work!=tmp+sz1?1:0;
1635                 }
1636               else
1637                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1638             }
1639           else
1640             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1641         }
1642     }
1643   return 0;
1644 }
1645
1646 /*!
1647  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1648  */
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1650 {
1651   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1652     {
1653       if(conn[connI[cell1]]==conn[connI[cell2]])
1654         {
1655           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1657           return s1==s2?1:0;
1658         }
1659     }
1660   return 0;
1661 }
1662
1663 /*!
1664  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1665  */
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1667 {
1668   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1669     {
1670       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1672       return s1==s2?1:0;
1673     }
1674   return 0;
1675 }
1676
1677 /*!
1678  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1679  */
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1681 {
1682   mcIdType sz=connI[cell1+1]-connI[cell1];
1683   if(sz==connI[cell2+1]-connI[cell2])
1684     {
1685       if(conn[connI[cell1]]==conn[connI[cell2]])
1686         {
1687           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688           unsigned dim=cm.getDimension();
1689           if(dim!=3)
1690             {
1691               if(dim!=1)
1692                 {
1693                   mcIdType sz1=2*(sz-1);
1694                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1698                   if(work!=tmp+sz1)
1699                     return 1;
1700                   else
1701                     {
1702                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1705                         return 2;
1706                       else
1707                         return 0;
1708                     }
1709                 }
1710               else
1711                 {//case of SEG2 and SEG3
1712                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1713                     return 1;
1714                   if(!cm.isQuadratic())
1715                     {
1716                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1719                         return 2;
1720                       return 0;
1721                     }
1722                   else
1723                     {
1724                       if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1725                         return 2;
1726                       return 0;
1727                     }
1728                 }
1729             }
1730           else
1731             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 /*!
1739  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741  * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743  * This method is time consuming.
1744  *
1745  * \param [in] compType input specifying the technique used to compare cells each other.
1746  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750  * can be used for users not sensitive to orientation of cell
1751  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1754  *
1755  */
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1757 {
1758   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759   getReverseNodalConnectivity(revNodal,revNodalI);
1760   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1761 }
1762
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1765 {
1766   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771   std::vector<bool> isFetched(nbOfCells,false);
1772   if(startCellId==0)
1773     {
1774       for(mcIdType i=startCellId;i<nbOfCells;i++)
1775         {
1776           if(!isFetched[i])
1777             {
1778               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779               std::vector<mcIdType> v,v2;
1780               if(connOfNode!=connPtr+connIPtr[i+1])
1781                 {
1782                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1784                   connOfNode++;
1785                 }
1786               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1787                 if(*connOfNode>=0)
1788                   {
1789                     v=v2;
1790                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792                     v2.resize(std::distance(v2.begin(),it));
1793                   }
1794               if(v2.size()>1)
1795                 {
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType pos=commonCellsI->back();
1799                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   else
1808     {
1809       for(mcIdType i=startCellId;i<nbOfCells;i++)
1810         {
1811           if(!isFetched[i])
1812             {
1813               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815               std::vector<mcIdType> v,v2;
1816               if(connOfNode!=connPtr+connIPtr[i+1])
1817                 {
1818                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1819                   connOfNode++;
1820                 }
1821               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1822                 if(*connOfNode>=0)
1823                   {
1824                     v=v2;
1825                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826                     v2.resize(std::distance(v2.begin(),it));
1827                   }
1828               // v2 contains now candidates. Problem candidates are sorted using id rank.
1829               if(v2.size()>1)
1830                 {
1831                   if(v2[0]!=i)
1832                   {
1833                     auto it(std::find(v2.begin(),v2.end(),i));
1834                     std::swap(*v2.begin(),*it);
1835                   }
1836                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1837                     {
1838                       mcIdType newPos(commonCells->getNumberOfTuples());
1839                       mcIdType pos(commonCellsI->back());
1840                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841                       commonCellsI->pushBackSilent(newPos);
1842                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843                         isFetched[*it]=true;
1844                     }
1845                 }
1846             }
1847         }
1848     }
1849   commonCellsArr=commonCells.retn();
1850   commonCellsIArr=commonCellsI.retn();
1851 }
1852
1853 /*!
1854  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856  * than \a this->getNumberOfCells() in the returned array means that there is no
1857  * corresponding cell in \a this mesh.
1858  * It is expected that \a this and \a other meshes share the same node coordinates
1859  * array, if it is not so an exception is thrown.
1860  *  \param [in] other - the mesh to compare with.
1861  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1862  *         valid values [0,1,2], see zipConnectivityTraducer().
1863  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1865  *         values. The caller is to delete this array using
1866  *         decrRef() as it is no more needed.
1867  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1868  *         mesh.
1869  *
1870  *  \if ENABLE_EXAMPLES
1871  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1873  *  \endif
1874  *  \sa checkDeepEquivalOnSameNodesWith()
1875  *  \sa checkGeoEquivalWith()
1876  */
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1878 {
1879   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880   mcIdType nbOfCells=getNumberOfCells();
1881   static const int possibleCompType[]={0,1,2};
1882   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1883     {
1884       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1886       oss << " !";
1887       throw INTERP_KERNEL::Exception(oss.str());
1888     }
1889   //
1890   if(other->getNumberOfCells()==0)
1891   {
1892     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1893     return true;
1894   }
1895   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898   mcIdType newNbOfCells=-1;
1899   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901   mcIdType maxPart(p0->getMaxValueInArray());
1902   bool ret(maxPart==newNbOfCells-1);
1903   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904   // fill p1 array in case of presence of cells in other not in this
1905   mcIdType *pt(p1->getPointer());
1906   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1907     pt[i+1] = i+1;
1908   //
1909   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1911   arr = p2.retn();
1912   return ret;
1913 }
1914
1915 /*!
1916  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917  * This method tries to determine if \b other is fully included in \b this.
1918  * The main difference is that this method is not expected to throw exception.
1919  * This method has two outputs :
1920  *
1921  * \param other other mesh
1922  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1924  */
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1926 {
1927   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928   DataArrayIdType *commonCells=0,*commonCellsI=0;
1929   mcIdType thisNbCells=getNumberOfCells();
1930   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933   mcIdType otherNbCells=other->getNumberOfCells();
1934   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935   arr2->alloc(otherNbCells,1);
1936   arr2->fillWithZero();
1937   mcIdType *arr2Ptr=arr2->getPointer();
1938   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939   for(mcIdType i=0;i<nbOfCommon;i++)
1940     {
1941       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942       if(start<thisNbCells)
1943         {
1944           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1945             {
1946               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947               mcIdType val=std::abs(commonCellsPtr[j])-1;
1948               if(val>=thisNbCells)
1949                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1950             }
1951         }
1952     }
1953   arr2->setName(other->getName());
1954   if(arr2->presenceOfValue(0))
1955     return false;
1956   arr=arr2.retn();
1957   return true;
1958 }
1959
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1961 {
1962   if(!other)
1963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1965   if(!otherC)
1966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967   std::vector<const MEDCouplingUMesh *> ms(2);
1968   ms[0]=this;
1969   ms[1]=otherC;
1970   return MergeUMeshesOnSameCoords(ms);
1971 }
1972
1973 /*!
1974  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976  * cellIds is not given explicitly but by a range python like.
1977  *
1978  * \param start starting ID
1979  * \param end end ID (excluded)
1980  * \param step step size
1981  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982  * \return a newly allocated
1983  *
1984  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1986  */
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1988 {
1989   if(getMeshDimension()!=-1)
1990     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1991   else
1992     {
1993       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1994       if(newNbOfCells!=1)
1995         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1996       if(start!=0)
1997         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1998       incrRef();
1999       return const_cast<MEDCouplingUMesh *>(this);
2000     }
2001 }
2002
2003 /*!
2004  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005  * The result mesh shares or not the node coordinates array with \a this mesh depending
2006  * on \a keepCoords parameter.
2007  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008  *           to write this mesh to the MED file, its cells must be sorted using
2009  *           sortCellsInMEDFileFrmt().
2010  *  \param [in] begin - an array of cell ids to include to the new mesh.
2011  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2014  *         by calling zipCoords().
2015  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016  *         to delete this mesh using decrRef() as it is no more needed.
2017  *  \throw If the coordinates array is not set.
2018  *  \throw If the nodal connectivity of cells is not defined.
2019  *  \throw If any cell id in the array \a begin is not valid.
2020  *
2021  *  \if ENABLE_EXAMPLES
2022  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2024  *  \endif
2025  */
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2027 {
2028   if(getMeshDimension()!=-1)
2029     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2030   else
2031     {
2032       if(end-begin!=1)
2033         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2034       if(begin[0]!=0)
2035         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2036       incrRef();
2037       return const_cast<MEDCouplingUMesh *>(this);
2038     }
2039 }
2040
2041 /*!
2042  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2043  *
2044  * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046  * The number of cells of \b this will remain the same with this method.
2047  *
2048  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050  * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2052  */
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2054 {
2055   checkConnectivityFullyDefined();
2056   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2060     {
2061       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063       throw INTERP_KERNEL::Exception(oss.str());
2064     }
2065   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069       throw INTERP_KERNEL::Exception(oss.str());
2070     }
2071   mcIdType nbOfCells(getNumberOfCells());
2072   bool easyAssign(true);
2073   const mcIdType *connI(_nodal_connec_index->begin());
2074   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2076     {
2077       if(*it>=0 && *it<nbOfCells)
2078         {
2079           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2080         }
2081       else
2082         {
2083           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084           throw INTERP_KERNEL::Exception(oss.str());
2085         }
2086     }
2087   if(easyAssign)
2088     {
2089       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2090       computeTypes();
2091     }
2092   else
2093     {
2094       DataArrayIdType *arrOut=0,*arrIOut=0;
2095       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2096                                                arrOut,arrIOut);
2097       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098       setConnectivity(arrOut,arrIOut,true);
2099     }
2100 }
2101
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2103 {
2104   checkConnectivityFullyDefined();
2105   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2109     {
2110       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112       throw INTERP_KERNEL::Exception(oss.str());
2113     }
2114   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118       throw INTERP_KERNEL::Exception(oss.str());
2119     }
2120   mcIdType nbOfCells=getNumberOfCells();
2121   bool easyAssign=true;
2122   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2124   mcIdType it=start;
2125   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2126     {
2127       if(it>=0 && it<nbOfCells)
2128         {
2129           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2130         }
2131       else
2132         {
2133           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134           throw INTERP_KERNEL::Exception(oss.str());
2135         }
2136     }
2137   if(easyAssign)
2138     {
2139       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2140       computeTypes();
2141     }
2142   else
2143     {
2144       DataArrayIdType *arrOut=0,*arrIOut=0;
2145       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2146                                                 arrOut,arrIOut);
2147       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148       setConnectivity(arrOut,arrIOut,true);
2149     }
2150 }
2151
2152
2153 /*!
2154  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155  * this->getMeshDimension(), that bound some cells of \a this mesh.
2156  * The cells of lower dimension to include to the result mesh are selected basing on
2157  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160  * created mesh shares the node coordinates array with \a this mesh.
2161  *  \param [in] begin - the array of node ids.
2162  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164  *         array \a begin are added, else cells whose any node is in the
2165  *         array \a begin are added.
2166  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167  *         to delete this mesh using decrRef() as it is no more needed.
2168  *  \throw If the coordinates array is not set.
2169  *  \throw If the nodal connectivity of cells is not defined.
2170  *  \throw If any node id in \a begin is not valid.
2171  *
2172  *  \if ENABLE_EXAMPLES
2173  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2175  *  \endif
2176  */
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2178 {
2179   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2184 }
2185
2186 /*!
2187  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2191  *         by calling zipCoords().
2192  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193  *         to delete this mesh using decrRef() as it is no more needed.
2194  *  \throw If the coordinates array is not set.
2195  *  \throw If the nodal connectivity of cells is not defined.
2196  *
2197  *  \if ENABLE_EXAMPLES
2198  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2200  *  \endif
2201  */
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2203 {
2204   DataArrayIdType *desc=DataArrayIdType::New();
2205   DataArrayIdType *descIndx=DataArrayIdType::New();
2206   DataArrayIdType *revDesc=DataArrayIdType::New();
2207   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2208   //
2209   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2210   revDesc->decrRef();
2211   desc->decrRef();
2212   descIndx->decrRef();
2213   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215   std::vector<mcIdType> boundaryCells;
2216   for(mcIdType i=0;i<nbOfCells;i++)
2217     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218       boundaryCells.push_back(i);
2219   revDescIndx->decrRef();
2220   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2221   return ret;
2222 }
2223
2224 /*!
2225  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2228  */
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2230 {
2231   checkFullyDefined();
2232   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2236   //
2237   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2239   //
2240   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242   const mcIdType *revDescPtr=revDesc->getConstPointer();
2243   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244   mcIdType nbOfCells=getNumberOfCells();
2245   std::vector<bool> ret1(nbOfCells,false);
2246   mcIdType sz=0;
2247   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2250   //
2251   DataArrayIdType *ret2=DataArrayIdType::New();
2252   ret2->alloc(sz,1);
2253   mcIdType *ret2Ptr=ret2->getPointer();
2254   sz=0;
2255   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2256     if(*it)
2257       *ret2Ptr++=sz;
2258   ret2->setName("BoundaryCells");
2259   return ret2;
2260 }
2261
2262 /*!
2263  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2267  *
2268  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269  * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2270  * equals a cell in \b otherDimM1OnSameCoords.
2271  *
2272  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2274  *
2275  * \param [in] otherDimM1OnSameCoords other mesh
2276  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277  * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2278  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2279  */
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2281 {
2282   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284   checkConnectivityFullyDefined();
2285   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294   DataArrayIdType *idsOtherInConsti=0;
2295   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2297   if(!b)
2298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299   std::set<mcIdType> s1;
2300   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303   s1arr_renum1->sort();
2304   cellIdsRk0=s0arr.retn();
2305   //cellIdsRk1=s_renum1.retn();
2306   cellIdsRk1=s1arr_renum1.retn();
2307 }
2308
2309 /*!
2310  * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2311  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2312  *
2313  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2314  */
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2316 {
2317   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2321   //
2322   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323   revDesc=0; desc=0; descIndx=0;
2324   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2327 }
2328
2329 /*!
2330  * Finds nodes lying on the boundary of \a this mesh.
2331  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332  *          nodes. The caller is to delete this array using decrRef() as it is no
2333  *          more needed.
2334  *  \throw If the coordinates array is not set.
2335  *  \throw If the nodal connectivity of cells is node defined.
2336  *
2337  *  \if ENABLE_EXAMPLES
2338  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2340  *  \endif
2341  */
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2343 {
2344   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345   return skin->computeFetchedNodeIds();
2346 }
2347
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2349 {
2350   incrRef();
2351   return const_cast<MEDCouplingUMesh *>(this);
2352 }
2353
2354 /*!
2355  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2358  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2359  * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2360  *
2361  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2362  *             parameter is altered during the call.
2363  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2364  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2365  * \param [out] cellIdsNotModified cell ids mcIdType \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2366  *
2367  */
2368 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2369                                             DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2370 {
2371   typedef MCAuto<DataArrayIdType> DAInt;
2372   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2373
2374   checkFullyDefined();
2375   otherDimM1OnSameCoords.checkFullyDefined();
2376   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2377     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2378   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2379     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2380
2381   // Checking star-shaped M1 group:
2382   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2383   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2384   DAInt dsi = rdit0->deltaShiftIndex();
2385   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.
2386   if(idsTmp0->getNumberOfTuples())
2387     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2388   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2389
2390   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2391   // ie nodes belonging to the boundary "cells" (might be points) of M1
2392   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2393   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2394   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2395   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2396   dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2397   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2398   dsi = rdit0->deltaShiftIndex();
2399   DAInt boundSegs = dsi->findIdsEqual(1);  dsi = 0; // boundary segs/faces of the M0 mesh
2400   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2401   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2402   // 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)
2403   // 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
2404   // although they are technically on the skin of the cube.
2405   DAInt notDup = 0;
2406   if (getMeshDimension() == 3)
2407     {
2408       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2409       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2410       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2411       DataArrayIdType * corresp=0;
2412       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2413       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2414       corresp->decrRef();
2415       if (validIds->getNumberOfTuples())
2416         {
2417           // 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:
2418           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2419           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2420           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2421           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2422
2423           // Also, in this (segment) mesh, nodes connected to more than 3 segs should not be dup either (singular points - see testBuildInnerBoundary6())
2424           dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2425           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;  // a mesh made of node cells
2426           dsi = rdit0->deltaShiftIndex();
2427           DAInt singPoints = dsi->findIdsNotInRange(-1,4);   // points connected to (strictly) more than 3 segments
2428           const mcIdType *cc = meshM2Desc->getNodalConnectivity()->begin(), *ccI = meshM2Desc->getNodalConnectivityIndex()->begin();
2429           mcIdType * singPointsP = singPoints->rwBegin();
2430           for (mcIdType j=0; j < singPoints->getNumberOfTuples(); j++) // replace ids in singPoints by real coordinate index (was index of cells in notDuplSkin)
2431             {
2432               mcIdType nodeCellIdx = singPointsP[j];
2433               singPointsP[j] = cc[ccI[nodeCellIdx]+1];  // +1 to skip type
2434             }
2435           DAInt fNodes2 = fNodes1->buildSubstraction(singPoints);
2436           notDup = xtrem->buildSubstraction(fNodes2);
2437         }
2438       else
2439         notDup = xtrem->buildSubstraction(fNodes);
2440     }
2441   else
2442     notDup = xtrem->buildSubstraction(fNodes);
2443
2444   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2445   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2446   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2447   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2448
2449   //
2450   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2451   mcIdType nCells2 = m0Part2->getNumberOfCells();
2452   DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2453   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2454
2455   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2456   DataArrayIdType *tmp00=0,*tmp11=0;
2457   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2458   DAInt neighInit00(tmp00);
2459   DAInt neighIInit00(tmp11);
2460   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2461   DataArrayIdType *idsTmp=0;
2462   m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2463   DAInt ids(idsTmp);
2464   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2465   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2466   DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2467   DataArrayIdType *tmp0=0,*tmp1=0;
2468   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2469   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2470   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2471   DAInt neigh00(tmp0);
2472   DAInt neighI00(tmp1);
2473
2474   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2475   mcIdType seed = 0, nIter = 0;
2476   mcIdType nIterMax = nCells2+1; // Safety net for the loop
2477   DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2478   hitCells->fillWithValue(-1);
2479   DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2480   cellsToModifyConn0_torenum->alloc(0,1);
2481   while (nIter < nIterMax)
2482     {
2483       DAInt t = hitCells->findIdsEqual(-1);
2484       if (!t->getNumberOfTuples())
2485         break;
2486       // Connex zone without the crack (to compute the next seed really)
2487       mcIdType dnu;
2488       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2489       mcIdType cnt(0);
2490       for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2491         hitCells->setIJ(*ptr,0,1);
2492       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2493       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2494       cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2495       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2496       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2497       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2498       DAInt intersec = nonHitCells->buildIntersection(comple);
2499       if (intersec->getNumberOfTuples())
2500         { seed = intersec->getIJ(0,0); }
2501       else
2502         { break; }
2503       nIter++;
2504     }
2505   if (nIter >= nIterMax)
2506     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2507
2508   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2509   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2510   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2511   //
2512   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2513   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2514   nodeIdsToDuplicate=dupl.retn();
2515 }
2516
2517 /*!
2518  * This method operates a modification of the connectivity and coords in \b this.
2519  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2520  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2521  * 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
2522  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2523  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2524  *
2525  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2526  *
2527  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2528  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2529  */
2530 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2531 {
2532   mcIdType nbOfNodes=getNumberOfNodes();
2533   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2534   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2535 }
2536
2537 /*!
2538  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2539  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2540  *
2541  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2542  *
2543  * \sa renumberNodesInConn
2544  */
2545 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2546 {
2547   checkConnectivityFullyDefined();
2548   mcIdType *conn(getNodalConnectivity()->getPointer());
2549   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2550   mcIdType nbOfCells=getNumberOfCells();
2551   for(mcIdType i=0;i<nbOfCells;i++)
2552     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2553       {
2554         mcIdType& node=conn[iconn];
2555         if(node>=0)//avoid polyhedron separator
2556           {
2557             node+=offset;
2558           }
2559       }
2560   _nodal_connec->declareAsNew();
2561   updateTime();
2562 }
2563
2564 /*!
2565  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2566  *  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
2567  *  of a big mesh.
2568  */
2569 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2570 {
2571   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2572 }
2573
2574 /*!
2575  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2576  *  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
2577  *  of a big mesh.
2578  */
2579 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2580 {
2581   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2582 }
2583
2584 /*!
2585  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2586  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2587  * This method is a generalization of shiftNodeNumbersInConn().
2588  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2589  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2590  *         this->getNumberOfNodes(), in "Old to New" mode.
2591  *         See \ref numbering for more info on renumbering modes.
2592  *  \throw If the nodal connectivity of cells is not defined.
2593  *
2594  *  \if ENABLE_EXAMPLES
2595  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2596  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2597  *  \endif
2598  */
2599 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2600 {
2601   checkConnectivityFullyDefined();
2602   mcIdType *conn=getNodalConnectivity()->getPointer();
2603   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2604   mcIdType nbOfCells=getNumberOfCells();
2605   for(mcIdType i=0;i<nbOfCells;i++)
2606     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2607       {
2608         mcIdType& node=conn[iconn];
2609         if(node>=0)//avoid polyhedron separator
2610           {
2611             node=newNodeNumbersO2N[node];
2612           }
2613       }
2614   _nodal_connec->declareAsNew();
2615   updateTime();
2616 }
2617
2618 /*!
2619  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2620  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2621  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2622  *
2623  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2624  */
2625 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2626 {
2627   checkConnectivityFullyDefined();
2628   mcIdType *conn=getNodalConnectivity()->getPointer();
2629   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2630   mcIdType nbOfCells=getNumberOfCells();
2631   for(mcIdType i=0;i<nbOfCells;i++)
2632     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2633       {
2634         mcIdType& node=conn[iconn];
2635         if(node>=0)//avoid polyhedron separator
2636           {
2637             node+=delta;
2638           }
2639       }
2640   _nodal_connec->declareAsNew();
2641   updateTime();
2642 }
2643
2644 /*!
2645  * This method operates a modification of the connectivity in \b this.
2646  * 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.
2647  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2648  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2649  * 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
2650  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2651  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2652  *
2653  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2654  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2655  *
2656  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2657  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2658  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2659  */
2660 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2661 {
2662   checkConnectivityFullyDefined();
2663   std::map<mcIdType,mcIdType> m;
2664   mcIdType val=offset;
2665   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2666     m[*work]=val;
2667   mcIdType *conn=getNodalConnectivity()->getPointer();
2668   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2669   mcIdType nbOfCells=getNumberOfCells();
2670   for(mcIdType i=0;i<nbOfCells;i++)
2671     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2672       {
2673         mcIdType& node=conn[iconn];
2674         if(node>=0)//avoid polyhedron separator
2675           {
2676             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2677             if(it!=m.end())
2678               node=(*it).second;
2679           }
2680       }
2681   updateTime();
2682 }
2683
2684 /*!
2685  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2686  *
2687  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2688  * After the call of this method the number of cells remains the same as before.
2689  *
2690  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2691  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2692  * be strictly in [0;this->getNumberOfCells()).
2693  *
2694  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2695  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2696  * should be contained in[0;this->getNumberOfCells()).
2697  *
2698  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2699  * \param check whether to check content of old2NewBg
2700  */
2701 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2702 {
2703   checkConnectivityFullyDefined();
2704   mcIdType nbCells=getNumberOfCells();
2705   const mcIdType *array=old2NewBg;
2706   if(check)
2707     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2708   //
2709   const mcIdType *conn=_nodal_connec->getConstPointer();
2710   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2711   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2712   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2713   const mcIdType *n2oPtr=n2o->begin();
2714   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2715   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2716   newConn->copyStringInfoFrom(*_nodal_connec);
2717   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2718   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2719   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2720   //
2721   mcIdType *newC=newConn->getPointer();
2722   mcIdType *newCI=newConnI->getPointer();
2723   mcIdType loc=0;
2724   newCI[0]=loc;
2725   for(mcIdType i=0;i<nbCells;i++)
2726     {
2727       mcIdType pos=n2oPtr[i];
2728       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2729       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2730       loc+=nbOfElts;
2731       newCI[i+1]=loc;
2732     }
2733   //
2734   setConnectivity(newConn,newConnI);
2735   if(check)
2736     free(const_cast<mcIdType *>(array));
2737 }
2738
2739 /*!
2740  * Finds cells whose bounding boxes intersect a given bounding box.
2741  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2742  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2743  *         zMax (if in 3D).
2744  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2745  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2746  *         extent of the bounding box of cell to produce an addition to this bounding box.
2747  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2748  *         cells. The caller is to delete this array using decrRef() as it is no more
2749  *         needed.
2750  *  \throw If the coordinates array is not set.
2751  *  \throw If the nodal connectivity of cells is not defined.
2752  *
2753  *  \if ENABLE_EXAMPLES
2754  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2755  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2756  *  \endif
2757  */
2758 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2759 {
2760   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2761   if(getMeshDimension()==-1)
2762     {
2763       elems->pushBackSilent(0);
2764       return elems.retn();
2765     }
2766   int dim=getSpaceDimension();
2767   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2768   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2769   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2770   const double* coords = getCoords()->getConstPointer();
2771   mcIdType nbOfCells=getNumberOfCells();
2772   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2773     {
2774       for (int i=0; i<dim; i++)
2775         {
2776           elem_bb[i*2]=std::numeric_limits<double>::max();
2777           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2778         }
2779
2780       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2781         {
2782           mcIdType node= conn[inode];
2783           if(node>=0)//avoid polyhedron separator
2784             {
2785               for (int idim=0; idim<dim; idim++)
2786                 {
2787                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2788                     {
2789                       elem_bb[idim*2] = coords[node*dim+idim] ;
2790                     }
2791                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2792                     {
2793                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2794                     }
2795                 }
2796             }
2797         }
2798       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2799         elems->pushBackSilent(ielem);
2800     }
2801   return elems.retn();
2802 }
2803
2804 /*!
2805  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2806  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2807  * added in 'elems' parameter.
2808  */
2809 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2810 {
2811   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2812   if(getMeshDimension()==-1)
2813     {
2814       elems->pushBackSilent(0);
2815       return elems.retn();
2816     }
2817   int dim=getSpaceDimension();
2818   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2819   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2820   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2821   const double* coords = getCoords()->getConstPointer();
2822   mcIdType nbOfCells=getNumberOfCells();
2823   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2824     {
2825       for (int i=0; i<dim; i++)
2826         {
2827           elem_bb[i*2]=std::numeric_limits<double>::max();
2828           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2829         }
2830
2831       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2832         {
2833           mcIdType node= conn[inode];
2834           if(node>=0)//avoid polyhedron separator
2835             {
2836               for (int idim=0; idim<dim; idim++)
2837                 {
2838                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2839                     {
2840                       elem_bb[idim*2] = coords[node*dim+idim] ;
2841                     }
2842                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2843                     {
2844                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2845                     }
2846                 }
2847             }
2848         }
2849       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2850         elems->pushBackSilent(ielem);
2851     }
2852   return elems.retn();
2853 }
2854
2855 /*!
2856  * Returns a type of a cell by its id.
2857  *  \param [in] cellId - the id of the cell of interest.
2858  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2859  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2860  */
2861 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2862 {
2863   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2864   if(cellId<_nodal_connec_index->getNbOfElems()-1)
2865     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2866   else
2867     {
2868       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2869       throw INTERP_KERNEL::Exception(oss.str());
2870     }
2871 }
2872
2873 /*!
2874  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2875  * This method does not throw exception if geometric type \a type is not in \a this.
2876  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2877  * The coordinates array is not considered here.
2878  *
2879  * \param [in] type the geometric type
2880  * \return cell ids in this having geometric type \a type.
2881  */
2882 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2883 {
2884
2885   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2886   ret->alloc(0,1);
2887   checkConnectivityFullyDefined();
2888   mcIdType nbCells=getNumberOfCells();
2889   int mdim=getMeshDimension();
2890   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2891   if(mdim!=ToIdType(cm.getDimension()))
2892     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2893   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2894   const mcIdType *pt=_nodal_connec->getConstPointer();
2895   for(mcIdType i=0;i<nbCells;i++)
2896     {
2897       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2898         ret->pushBackSilent(i);
2899     }
2900   return ret.retn();
2901 }
2902
2903 /*!
2904  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2905  */
2906 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2907 {
2908   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2909   mcIdType nbOfCells(getNumberOfCells()),ret(0);
2910   for(mcIdType i=0;i<nbOfCells;i++)
2911     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2912       ret++;
2913   return ret;
2914 }
2915
2916 /*!
2917  * Returns the nodal connectivity of a given cell.
2918  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2919  * all returned node ids can be used in getCoordinatesOfNode().
2920  *  \param [in] cellId - an id of the cell of interest.
2921  *  \param [in,out] conn - a vector where the node ids are appended. It is not
2922  *         cleared before the appending.
2923  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2924  */
2925 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2926 {
2927   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2928   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2929     if(*w>=0)
2930       conn.push_back(*w);
2931 }
2932
2933 std::string MEDCouplingUMesh::simpleRepr() const
2934 {
2935   static const char msg0[]="No coordinates specified !";
2936   std::ostringstream ret;
2937   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2938   ret << "Description of mesh : \"" << getDescription() << "\"\n";
2939   int tmpp1,tmpp2;
2940   double tt=getTime(tmpp1,tmpp2);
2941   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2942   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
2943   if(_mesh_dim>=-1)
2944     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2945   else
2946     { ret << " Mesh dimension has not been set or is invalid !"; }
2947   if(_coords!=0)
2948     {
2949       const int spaceDim=getSpaceDimension();
2950       ret << spaceDim << "\nInfo attached on space dimension : ";
2951       for(int i=0;i<spaceDim;i++)
2952         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2953       ret << "\n";
2954     }
2955   else
2956     ret << msg0 << "\n";
2957   ret << "Number of nodes : ";
2958   if(_coords!=0)
2959     ret << getNumberOfNodes() << "\n";
2960   else
2961     ret << msg0 << "\n";
2962   ret << "Number of cells : ";
2963   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2964     ret << getNumberOfCells() << "\n";
2965   else
2966     ret << "No connectivity specified !" << "\n";
2967   ret << "Cell types present : ";
2968   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2969     {
2970       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2971       ret << cm.getRepr() << " ";
2972     }
2973   ret << "\n";
2974   return ret.str();
2975 }
2976
2977 std::string MEDCouplingUMesh::advancedRepr() const
2978 {
2979   std::ostringstream ret;
2980   ret << simpleRepr();
2981   ret << "\nCoordinates array : \n___________________\n\n";
2982   if(_coords)
2983     _coords->reprWithoutNameStream(ret);
2984   else
2985     ret << "No array set !\n";
2986   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2987   reprConnectivityOfThisLL(ret);
2988   return ret.str();
2989 }
2990
2991 /*!
2992  * This method returns a C++ code that is a dump of \a this.
2993  * This method will throw if this is not fully defined.
2994  */
2995 std::string MEDCouplingUMesh::cppRepr() const
2996 {
2997   static const char coordsName[]="coords";
2998   static const char connName[]="conn";
2999   static const char connIName[]="connI";
3000   checkFullyDefined();
3001   std::ostringstream ret; ret << "// coordinates" << std::endl;
3002   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3003   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3004   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3005   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3006   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3007   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3008   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3009   return ret.str();
3010 }
3011
3012 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3013 {
3014   std::ostringstream ret;
3015   reprConnectivityOfThisLL(ret);
3016   return ret.str();
3017 }
3018
3019 /*!
3020  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3021  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3022  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3023  * some algos).
3024  *
3025  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3026  * 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
3027  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3028  */
3029 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3030 {
3031   int mdim=getMeshDimension();
3032   if(mdim<0)
3033     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3034   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3035   MCAuto<DataArrayIdType> tmp1,tmp2;
3036   bool needToCpyCT=true;
3037   if(!_nodal_connec)
3038     {
3039       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3040       needToCpyCT=false;
3041     }
3042   else
3043     {
3044       tmp1=_nodal_connec;
3045       tmp1->incrRef();
3046     }
3047   if(!_nodal_connec_index)
3048     {
3049       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3050       needToCpyCT=false;
3051     }
3052   else
3053     {
3054       tmp2=_nodal_connec_index;
3055       tmp2->incrRef();
3056     }
3057   ret->setConnectivity(tmp1,tmp2,false);
3058   if(needToCpyCT)
3059     ret->_types=_types;
3060   if(!_coords)
3061     {
3062       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3063       ret->setCoords(coords);
3064     }
3065   else
3066     ret->setCoords(_coords);
3067   return ret.retn();
3068 }
3069
3070 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3071 {
3072   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3073   const mcIdType *pt=_nodal_connec->getConstPointer();
3074   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3075     return ptI[cellId+1]-ptI[cellId]-1;
3076   else
3077     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3078 }
3079
3080 /*!
3081  * Returns types of cells of the specified part of \a this mesh.
3082  * This method avoids computing sub-mesh explicitly to get its types.
3083  *  \param [in] begin - an array of cell ids of interest.
3084  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3085  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3086  *         describing the cell types.
3087  *  \throw If the coordinates array is not set.
3088  *  \throw If the nodal connectivity of cells is not defined.
3089  *  \sa getAllGeoTypes()
3090  */
3091 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3092 {
3093   checkFullyDefined();
3094   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3095   const mcIdType *conn=_nodal_connec->getConstPointer();
3096   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3097   for(const mcIdType *w=begin;w!=end;w++)
3098     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3099   return ret;
3100 }
3101
3102 /*!
3103  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3104  * Optionally updates
3105  * a set of types of cells constituting \a this mesh.
3106  * This method is for advanced users having prepared their connectivity before. For
3107  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3108  *  \param [in] conn - the nodal connectivity array.
3109  *  \param [in] connIndex - the nodal connectivity index array.
3110  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3111  *         mesh is updated.
3112  */
3113 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3114 {
3115   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3116   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3117   if(isComputingTypes)
3118     computeTypes();
3119   declareAsNew();
3120 }
3121
3122 /*!
3123  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3124  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3125  */
3126 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3127     _nodal_connec(0),_nodal_connec_index(0),
3128     _types(other._types)
3129 {
3130   if(other._nodal_connec)
3131     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3132   if(other._nodal_connec_index)
3133     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3134 }
3135
3136 MEDCouplingUMesh::~MEDCouplingUMesh()
3137 {
3138   if(_nodal_connec)
3139     _nodal_connec->decrRef();
3140   if(_nodal_connec_index)
3141     _nodal_connec_index->decrRef();
3142 }
3143
3144 /*!
3145  * Recomputes a set of cell types of \a this mesh. For more info see
3146  * \ref MEDCouplingUMeshNodalConnectivity.
3147  */
3148 void MEDCouplingUMesh::computeTypes()
3149 {
3150   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3151 }
3152
3153
3154 /*!
3155  * Returns a number of cells constituting \a this mesh.
3156  *  \return mcIdType - the number of cells in \a this mesh.
3157  *  \throw If the nodal connectivity of cells is not defined.
3158  */
3159 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3160 {
3161   if(_nodal_connec_index)
3162     return _nodal_connec_index->getNumberOfTuples()-1;
3163   else
3164     if(_mesh_dim==-1)
3165       return 1;
3166     else
3167       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3168 }
3169
3170 /*!
3171  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3172  * mesh. For more info see \ref meshes.
3173  *  \return int - the dimension of \a this mesh.
3174  *  \throw If the mesh dimension is not defined using setMeshDimension().
3175  */
3176 int MEDCouplingUMesh::getMeshDimension() const
3177 {
3178   if(_mesh_dim<-1)
3179     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3180   return _mesh_dim;
3181 }
3182
3183 /*!
3184  * Returns a length of the nodal connectivity array.
3185  * This method is for test reason. Normally the integer returned is not useable by
3186  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3187  *  \return mcIdType - the length of the nodal connectivity array.
3188  */
3189 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3190 {
3191   return _nodal_connec->getNbOfElems();
3192 }
3193
3194 /*!
3195  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3196  */
3197 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3198 {
3199   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3200   tinyInfo.push_back(ToIdType(getMeshDimension()));
3201   tinyInfo.push_back(getNumberOfCells());
3202   if(_nodal_connec)
3203     tinyInfo.push_back(getNodalConnectivityArrayLen());
3204   else
3205     tinyInfo.push_back(-1);
3206 }
3207
3208 /*!
3209  * First step of unserialization process.
3210  */
3211 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3212 {
3213   return tinyInfo[6]<=0;
3214 }
3215
3216 /*!
3217  * Second step of serialization process.
3218  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3219  * \param a1 DataArrayDouble
3220  * \param a2 DataArrayDouble
3221  * \param littleStrings string vector
3222  */
3223 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3224 {
3225   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3226   if(tinyInfo[5]!=-1)
3227     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3228 }
3229
3230 /*!
3231  * Third and final step of serialization process.
3232  */
3233 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3234 {
3235   MEDCouplingPointSet::serialize(a1,a2);
3236   if(getMeshDimension()>-1)
3237     {
3238       a1=DataArrayIdType::New();
3239       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3240       mcIdType *ptA1=a1->getPointer();
3241       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3242       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3243       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3244       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3245     }
3246   else
3247     a1=0;
3248 }
3249
3250 /*!
3251  * Second and final unserialization process.
3252  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3253  */
3254 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3255 {
3256   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3257   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3258   if(tinyInfo[7]!=-1)
3259     {
3260       // Connectivity
3261       const mcIdType *recvBuffer=a1->getConstPointer();
3262       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3263       myConnecIndex->alloc(tinyInfo[6]+1,1);
3264       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3265       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3266       myConnec->alloc(tinyInfo[7],1);
3267       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3268       setConnectivity(myConnec, myConnecIndex);
3269     }
3270 }
3271
3272
3273
3274 /*!
3275  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3276  * mesh.<br>
3277  * For 1D cells, the returned field contains lengths.<br>
3278  * For 2D cells, the returned field contains areas.<br>
3279  * For 3D cells, the returned field contains volumes.
3280  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3281  *         orientation, i.e. the volume is always positive.
3282  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3283  *         and one time . The caller is to delete this field using decrRef() as it is no
3284  *         more needed.
3285  */
3286 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3287 {
3288   std::string name="MeasureOfMesh_";
3289   name+=getName();
3290   mcIdType nbelem=getNumberOfCells();
3291   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3292   field->setName(name);
3293   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3294   array->alloc(nbelem,1);
3295   double *area_vol=array->getPointer();
3296   field->setArray(array) ; array=0;
3297   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3298   field->synchronizeTimeWithMesh();
3299   if(getMeshDimension()!=-1)
3300     {
3301       mcIdType ipt;
3302       INTERP_KERNEL::NormalizedCellType type;
3303       int dim_space=getSpaceDimension();
3304       const double *coords=getCoords()->getConstPointer();
3305       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3306       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3307       for(mcIdType iel=0;iel<nbelem;iel++)
3308         {
3309           ipt=connec_index[iel];
3310           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3311           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);
3312         }
3313       if(isAbs)
3314         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3315     }
3316   else
3317     {
3318       area_vol[0]=std::numeric_limits<double>::max();
3319     }
3320   return field.retn();
3321 }
3322
3323 /*!
3324  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3325  * mesh.<br>
3326  * For 1D cells, the returned array contains lengths.<br>
3327  * For 2D cells, the returned array contains areas.<br>
3328  * For 3D cells, the returned array contains volumes.
3329  * This method avoids building explicitly a part of \a this mesh to perform the work.
3330  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3331  *         orientation, i.e. the volume is always positive.
3332  *  \param [in] begin - an array of cell ids of interest.
3333  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3334  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3335  *          delete this array using decrRef() as it is no more needed.
3336  *
3337  *  \if ENABLE_EXAMPLES
3338  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3339  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3340  *  \endif
3341  *  \sa getMeasureField()
3342  */
3343 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3344 {
3345   std::string name="PartMeasureOfMesh_";
3346   name+=getName();
3347   std::size_t nbelem=std::distance(begin,end);
3348   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3349   array->setName(name);
3350   array->alloc(nbelem,1);
3351   double *area_vol=array->getPointer();
3352   if(getMeshDimension()!=-1)
3353     {
3354       mcIdType ipt;
3355       INTERP_KERNEL::NormalizedCellType type;
3356       int dim_space=getSpaceDimension();
3357       const double *coords=getCoords()->getConstPointer();
3358       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3359       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3360       for(const mcIdType *iel=begin;iel!=end;iel++)
3361         {
3362           ipt=connec_index[*iel];
3363           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3364           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3365         }
3366       if(isAbs)
3367         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3368     }
3369   else
3370     {
3371       area_vol[0]=std::numeric_limits<double>::max();
3372     }
3373   return array.retn();
3374 }
3375
3376 /*!
3377  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3378  * \a this one. The returned field contains the dual cell volume for each corresponding
3379  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3380  *  the dual mesh in P1 sens of \a this.<br>
3381  * For 1D cells, the returned field contains lengths.<br>
3382  * For 2D cells, the returned field contains areas.<br>
3383  * For 3D cells, the returned field contains volumes.
3384  * This method is useful to check "P1*" conservative interpolators.
3385  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3386  *         orientation, i.e. the volume is always positive.
3387  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3388  *          nodes and one time. The caller is to delete this array using decrRef() as
3389  *          it is no more needed.
3390  */
3391 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3392 {
3393   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3394   std::string name="MeasureOnNodeOfMesh_";
3395   name+=getName();
3396   mcIdType nbNodes=getNumberOfNodes();
3397   MCAuto<DataArrayDouble> nnpc;
3398   {
3399     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3400     nnpc=tmp2->convertToDblArr();
3401   }
3402   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3403   const double *nnpcPtr(nnpc->begin());
3404   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3405   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3406   array->alloc(nbNodes,1);
3407   double *valsToFill=array->getPointer();
3408   std::fill(valsToFill,valsToFill+nbNodes,0.);
3409   const double *values=tmp->getArray()->getConstPointer();
3410   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3411   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3412   getReverseNodalConnectivity(da,daInd);
3413   const mcIdType *daPtr=da->getConstPointer();
3414   const mcIdType *daIPtr=daInd->getConstPointer();
3415   for(mcIdType i=0;i<nbNodes;i++)
3416     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3417       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3418   ret->setMesh(this);
3419   ret->setArray(array);
3420   return ret.retn();
3421 }
3422
3423 /*!
3424  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3425  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3426  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3427  * and are normalized.
3428  * <br> \a this can be either
3429  * - a  2D mesh in 2D or 3D space or
3430  * - an 1D mesh in 2D space.
3431  *
3432  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3433  *          cells and one time. The caller is to delete this field using decrRef() as
3434  *          it is no more needed.
3435  *  \throw If the nodal connectivity of cells is not defined.
3436  *  \throw If the coordinates array is not set.
3437  *  \throw If the mesh dimension is not set.
3438  *  \throw If the mesh and space dimension is not as specified above.
3439  */
3440 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3441 {
3442   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3443     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3444   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3445   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3446   mcIdType nbOfCells=getNumberOfCells();
3447   int nbComp=getMeshDimension()+1;
3448   array->alloc(nbOfCells,nbComp);
3449   double *vals=array->getPointer();
3450   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3451   const mcIdType *conn=_nodal_connec->getConstPointer();
3452   const double *coords=_coords->getConstPointer();
3453   if(getMeshDimension()==2)
3454     {
3455       if(getSpaceDimension()==3)
3456         {
3457           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3458           const double *locPtr=loc->getConstPointer();
3459           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3460             {
3461               mcIdType offset=connI[i];
3462               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3463               double n=INTERP_KERNEL::norm<3>(vals);
3464               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3465             }
3466         }
3467       else
3468         {
3469           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3470           const double *isAbsPtr=isAbs->getArray()->begin();
3471           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3472             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3473         }
3474     }
3475   else//meshdimension==1
3476     {
3477       double tmp[2];
3478       for(mcIdType i=0;i<nbOfCells;i++)
3479         {
3480           mcIdType offset=connI[i];
3481           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3482           double n=INTERP_KERNEL::norm<2>(tmp);
3483           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3484           *vals++=-tmp[1];
3485           *vals++=tmp[0];
3486         }
3487     }
3488   ret->setArray(array);
3489   ret->setMesh(this);
3490   ret->synchronizeTimeWithSupport();
3491   return ret.retn();
3492 }
3493
3494 /*!
3495  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3496  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3497  * and are normalized.
3498  * <br> \a this can be either
3499  * - a  2D mesh in 2D or 3D space or
3500  * - an 1D mesh in 2D space.
3501  *
3502  * This method avoids building explicitly a part of \a this mesh to perform the work.
3503  *  \param [in] begin - an array of cell ids of interest.
3504  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3505  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3506  *          cells and one time. The caller is to delete this field using decrRef() as
3507  *          it is no more needed.
3508  *  \throw If the nodal connectivity of cells is not defined.
3509  *  \throw If the coordinates array is not set.
3510  *  \throw If the mesh dimension is not set.
3511  *  \throw If the mesh and space dimension is not as specified above.
3512  *  \sa buildOrthogonalField()
3513  *
3514  *  \if ENABLE_EXAMPLES
3515  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3516  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3517  *  \endif
3518  */
3519 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3520 {
3521   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3522     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3523   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3524   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3525   std::size_t nbelems=std::distance(begin,end);
3526   int nbComp=getMeshDimension()+1;
3527   array->alloc(nbelems,nbComp);
3528   double *vals=array->getPointer();
3529   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3530   const mcIdType *conn=_nodal_connec->getConstPointer();
3531   const double *coords=_coords->getConstPointer();
3532   if(getMeshDimension()==2)
3533     {
3534       if(getSpaceDimension()==3)
3535         {
3536           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3537           const double *locPtr=loc->getConstPointer();
3538           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3539             {
3540               mcIdType offset=connI[*i];
3541               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3542               double n=INTERP_KERNEL::norm<3>(vals);
3543               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3544             }
3545         }
3546       else
3547         {
3548           for(std::size_t i=0;i<nbelems;i++)
3549             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3550         }
3551     }
3552   else//meshdimension==1
3553     {
3554       double tmp[2];
3555       for(const mcIdType *i=begin;i!=end;i++)
3556         {
3557           mcIdType offset=connI[*i];
3558           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3559           double n=INTERP_KERNEL::norm<2>(tmp);
3560           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3561           *vals++=-tmp[1];
3562           *vals++=tmp[0];
3563         }
3564     }
3565   ret->setArray(array);
3566   ret->setMesh(this);
3567   ret->synchronizeTimeWithSupport();
3568   return ret.retn();
3569 }
3570
3571 /*!
3572  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3573  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3574  * and are \b not normalized.
3575  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3576  *          cells and one time. The caller is to delete this field using decrRef() as
3577  *          it is no more needed.
3578  *  \throw If the nodal connectivity of cells is not defined.
3579  *  \throw If the coordinates array is not set.
3580  *  \throw If \a this->getMeshDimension() != 1.
3581  *  \throw If \a this mesh includes cells of type other than SEG2.
3582  */
3583 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3584 {
3585   if(getMeshDimension()!=1)
3586     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3587   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3588     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3589   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3590   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3591   mcIdType nbOfCells=getNumberOfCells();
3592   int spaceDim=getSpaceDimension();
3593   array->alloc(nbOfCells,spaceDim);
3594   double *pt=array->getPointer();
3595   const double *coo=getCoords()->getConstPointer();
3596   std::vector<mcIdType> conn;
3597   conn.reserve(2);
3598   for(mcIdType i=0;i<nbOfCells;i++)
3599     {
3600       conn.resize(0);
3601       getNodeIdsOfCell(i,conn);
3602       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3603     }
3604   ret->setArray(array);
3605   ret->setMesh(this);
3606   ret->synchronizeTimeWithSupport();
3607   return ret.retn();
3608 }
3609
3610 /*!
3611  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3612  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3613  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3614  * from. If a result face is shared by two 3D cells, then the face in included twice in
3615  * the result mesh.
3616  *  \param [in] origin - 3 components of a point defining location of the plane.
3617  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3618  *         must be greater than 1e-6.
3619  *  \param [in] eps - half-thickness of the plane.
3620  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3621  *         producing correspondent 2D cells. The caller is to delete this array
3622  *         using decrRef() as it is no more needed.
3623  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3624  *         not share the node coordinates array with \a this mesh. The caller is to
3625  *         delete this mesh using decrRef() as it is no more needed.
3626  *  \throw If the coordinates array is not set.
3627  *  \throw If the nodal connectivity of cells is not defined.
3628  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3629  *  \throw If magnitude of \a vec is less than 1e-6.
3630  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3631  *  \throw If \a this includes quadratic cells.
3632  */
3633 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3634 {
3635   checkFullyDefined();
3636   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3637     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3638   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3639   if(candidates->empty())
3640     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3641   std::vector<mcIdType> nodes;
3642   DataArrayIdType *cellIds1D=0;
3643   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3644   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3645   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3646   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3647   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3648   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3649   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3650   revDesc2=0; revDescIndx2=0;
3651   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3652   revDesc1=0; revDescIndx1=0;
3653   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3654   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3655   //
3656   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3657   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3658     cut3DCurve[*it]=-1;
3659   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3660   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3661   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3662                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3663                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3664   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3665   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3666   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3667   if(cellIds2->empty())
3668     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3669   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3670   ret->setCoords(mDesc1->getCoords());
3671   ret->setConnectivity(conn,connI,true);
3672   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3673   return ret.retn();
3674 }
3675
3676 /*!
3677  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3678 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
3679 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3680 the result mesh.
3681  *  \param [in] origin - 3 components of a point defining location of the plane.
3682  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3683  *         must be greater than 1e-6.
3684  *  \param [in] eps - half-thickness of the plane.
3685  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3686  *         producing correspondent segments. The caller is to delete this array
3687  *         using decrRef() as it is no more needed.
3688  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3689  *         mesh in 3D space. This mesh does not share the node coordinates array with
3690  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3691  *         no more needed.
3692  *  \throw If the coordinates array is not set.
3693  *  \throw If the nodal connectivity of cells is not defined.
3694  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3695  *  \throw If magnitude of \a vec is less than 1e-6.
3696  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3697  *  \throw If \a this includes quadratic cells.
3698  */
3699 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3700 {
3701   checkFullyDefined();
3702   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3703     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3704   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3705   if(candidates->empty())
3706     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3707   std::vector<mcIdType> nodes;
3708   DataArrayIdType *cellIds1D(0);
3709   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3710   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3711   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3712   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3713   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3714   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3715   //
3716   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3717   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3718     cut3DCurve[*it]=-1;
3719   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3720   mcIdType ncellsSub=subMesh->getNumberOfCells();
3721   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3722   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3723                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3724                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3725   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3726   conn->alloc(0,1);
3727   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3728   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3729   for(mcIdType i=0;i<ncellsSub;i++)
3730     {
3731       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3732         {
3733           if(cut3DSurf[i].first!=-2)
3734             {
3735               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3736               connI->pushBackSilent(conn->getNumberOfTuples());
3737               cellIds2->pushBackSilent(i);
3738             }
3739           else
3740             {
3741               mcIdType cellId3DSurf=cut3DSurf[i].second;
3742               mcIdType offset=nodalI[cellId3DSurf]+1;
3743               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3744               for(mcIdType j=0;j<nbOfEdges;j++)
3745                 {
3746                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3747                   connI->pushBackSilent(conn->getNumberOfTuples());
3748                   cellIds2->pushBackSilent(cellId3DSurf);
3749                 }
3750             }
3751         }
3752     }
3753   if(cellIds2->empty())
3754     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3755   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3756   ret->setCoords(mDesc1->getCoords());
3757   ret->setConnectivity(conn,connI,true);
3758   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3759   return ret.retn();
3760 }
3761
3762 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3763 {
3764   checkFullyDefined();
3765   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3766     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3767   if(getNumberOfCells()!=1)
3768     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3769   //
3770   std::vector<mcIdType> nodes;
3771   findNodesOnPlane(origin,vec,eps,nodes);
3772   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());
3773   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3774   revDesc2=0; revDescIndx2=0;
3775   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3776   revDesc1=0; revDescIndx1=0;
3777   DataArrayIdType *cellIds1D(0);
3778   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3779   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3780   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3781   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3782     cut3DCurve[*it]=-1;
3783   bool sameNbNodes;
3784   {
3785     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3786     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3787     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3788   }
3789   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3790   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3791                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3792                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3793   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3794   connI->pushBackSilent(0); conn->alloc(0,1);
3795   {
3796     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3797     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3798     if(cellIds2->empty())
3799       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3800   }
3801   std::vector<std::vector<mcIdType> > res;
3802   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3803   std::size_t sz(res.size());
3804   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3805     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3806   for(std::size_t i=0;i<sz;i++)
3807     {
3808       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3809       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3810       connI->pushBackSilent(conn->getNumberOfTuples());
3811     }
3812   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3813   ret->setCoords(mDesc1->getCoords());
3814   ret->setConnectivity(conn,connI,true);
3815   mcIdType nbCellsRet(ret->getNumberOfCells());
3816   //
3817   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3818   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3819   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3820   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3821   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3822   MCAuto<DataArrayDouble> occm;
3823   {
3824     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3825     occm=DataArrayDouble::Substract(ccm,pt);
3826   }
3827   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3828   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);
3829   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3830   //
3831   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3832   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3833   ret2->setCoords(mDesc1->getCoords());
3834   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3835   conn2I->pushBackSilent(0); conn2->alloc(0,1);
3836   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3837   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3838   if(dott->getIJ(0,0)>0)
3839     {
3840       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3841       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3842     }
3843   else
3844     {
3845       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3846       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3847     }
3848   for(mcIdType i=1;i<nbCellsRet;i++)
3849     {
3850       if(dott2->getIJ(i,0)<0)
3851         {
3852           if(ciPtr[i+1]-ciPtr[i]>=4)
3853             {
3854               cell0.push_back(-1);
3855               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3856             }
3857         }
3858       else
3859         {
3860           if(ciPtr[i+1]-ciPtr[i]>=4)
3861             {
3862               cell1.push_back(-1);
3863               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3864             }
3865         }
3866     }
3867   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3868   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3869   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3870   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3871   ret2->setConnectivity(conn2,conn2I,true);
3872   ret2->checkConsistencyLight();
3873   ret2->orientCorrectlyPolyhedrons();
3874   return ret2;
3875 }
3876
3877 /*!
3878  * Finds cells whose bounding boxes intersect a given plane.
3879  *  \param [in] origin - 3 components of a point defining location of the plane.
3880  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3881  *         must be greater than 1e-6.
3882  *  \param [in] eps - half-thickness of the plane.
3883  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3884  *         cells. The caller is to delete this array using decrRef() as it is no more
3885  *         needed.
3886  *  \throw If the coordinates array is not set.
3887  *  \throw If the nodal connectivity of cells is not defined.
3888  *  \throw If \a this->getSpaceDimension() != 3.
3889  *  \throw If magnitude of \a vec is less than 1e-6.
3890  *  \sa buildSlice3D()
3891  */
3892 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3893 {
3894   checkFullyDefined();
3895   if(getSpaceDimension()!=3)
3896     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3897   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3898   if(normm<1e-6)
3899     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3900   double vec2[3];
3901   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3902   double angle=acos(vec[2]/normm);
3903   MCAuto<DataArrayIdType> cellIds;
3904   double bbox[6];
3905   if(angle>eps)
3906     {
3907       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3908       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3909       if(normm2/normm>1e-6)
3910         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3911       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3912       mw->setCoords(coo);
3913       mw->getBoundingBox(bbox);
3914       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3915       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3916     }
3917   else
3918     {
3919       getBoundingBox(bbox);
3920       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3921       cellIds=getCellsInBoundingBox(bbox,eps);
3922     }
3923   return cellIds.retn();
3924 }
3925
3926 /*!
3927  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3928  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3929  * No consideration of coordinate is done by this method.
3930  * 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)
3931  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3932  */
3933 bool MEDCouplingUMesh::isContiguous1D() const
3934 {
3935   if(getMeshDimension()!=1)
3936     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3937   mcIdType nbCells=getNumberOfCells();
3938   if(nbCells<1)
3939     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3940   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3941   mcIdType ref=conn[connI[0]+2];
3942   for(mcIdType i=1;i<nbCells;i++)
3943     {
3944       if(conn[connI[i]+1]!=ref)
3945         return false;
3946       ref=conn[connI[i]+2];
3947     }
3948   return true;
3949 }
3950
3951 /*!
3952  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3953  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3954  * \param pt reference point of the line
3955  * \param v normalized director vector of the line
3956  * \param eps max precision before throwing an exception
3957  * \param res output of size this->getNumberOfCells
3958  */
3959 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3960 {
3961   if(getMeshDimension()!=1)
3962     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3963   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3964     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3965   if(getSpaceDimension()!=3)
3966     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3967   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3968   const double *fPtr=f->getArray()->getConstPointer();
3969   double tmp[3];
3970   for(mcIdType i=0;i<getNumberOfCells();i++)
3971     {
3972       const double *tmp1=fPtr+3*i;
3973       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3974       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3975       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3976       double n1=INTERP_KERNEL::norm<3>(tmp);
3977       n1/=INTERP_KERNEL::norm<3>(tmp1);
3978       if(n1>eps)
3979         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3980     }
3981   const double *coo=getCoords()->getConstPointer();
3982   for(mcIdType i=0;i<getNumberOfNodes();i++)
3983     {
3984       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3985       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3986       res[i]=std::accumulate(tmp,tmp+3,0.);
3987     }
3988 }
3989
3990 /*!
3991  * 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.
3992  * \a this is expected to be a mesh so that its space dimension is equal to its
3993  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3994  * 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).
3995  *
3996  * 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
3997  * 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).
3998  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3999  *
4000  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4001  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4002  *
4003  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4004  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4005  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4006  * \return the positive value of the distance.
4007  * \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
4008  * dimension - 1.
4009  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4010  */
4011 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4012 {
4013   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4014   if(meshDim!=spaceDim-1)
4015     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4016   if(meshDim!=2 && meshDim!=1)
4017     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4018   checkFullyDefined();
4019   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4020     { 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()); }
4021   DataArrayIdType *ret1=0;
4022   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4023   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4024   MCAuto<DataArrayIdType> ret1Safe(ret1);
4025   cellId=*ret1Safe->begin();
4026   return *ret0->begin();
4027 }
4028
4029 /*!
4030  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4031  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4032  * 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
4033  * 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).
4034  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4035  *
4036  * \a this is expected to be a mesh so that its space dimension is equal to its
4037  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4038  * 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).
4039  *
4040  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4041  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4042  *
4043  * \param [in] pts the list of points in which each tuple represents a point
4044  * \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.
4045  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4046  * \throw if number of components of \a pts is not equal to the space dimension.
4047  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4048  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4049  */
4050 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4051 {
4052   if(!pts)
4053     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4054   pts->checkAllocated();
4055   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4056   if(meshDim!=spaceDim-1)
4057     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4058   if(meshDim!=2 && meshDim!=1)
4059     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4060   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4061     {
4062       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4063       throw INTERP_KERNEL::Exception(oss.str());
4064     }
4065   checkFullyDefined();
4066   mcIdType nbCells=getNumberOfCells();
4067   if(nbCells==0)
4068     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4069   mcIdType nbOfPts=pts->getNumberOfTuples();
4070   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4071   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4072   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4073   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4074   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4075   const double *bbox(bboxArr->begin());
4076   switch(spaceDim)
4077   {
4078     case 3:
4079       {
4080         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4081         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4082           {
4083             double x=std::numeric_limits<double>::max();
4084             std::vector<mcIdType> elems;
4085             myTree.getMinDistanceOfMax(ptsPtr,x);
4086             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4087             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4088           }
4089         break;
4090       }
4091     case 2:
4092       {
4093         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4094         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4095           {
4096             double x=std::numeric_limits<double>::max();
4097             std::vector<mcIdType> elems;
4098             myTree.getMinDistanceOfMax(ptsPtr,x);
4099             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4100             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4101           }
4102         break;
4103       }
4104     default:
4105       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4106   }
4107   cellIds=ret1.retn();
4108   return ret0.retn();
4109 }
4110
4111 /// @cond INTERNAL
4112
4113 /// @endcond
4114
4115 /*!
4116  * Finds cells in contact with a ball (i.e. a point with precision).
4117  * 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.
4118  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4119  *
4120  * \warning This method is suitable if the caller intends to evaluate only one
4121  *          point, for more points getCellsContainingPoints() is recommended as it is
4122  *          faster.
4123  *  \param [in] pos - array of coordinates of the ball central point.
4124  *  \param [in] eps - ball radius.
4125  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4126  *         if there are no such cells.
4127  *  \throw If the coordinates array is not set.
4128  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4129  */
4130 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4131 {
4132   std::vector<mcIdType> elts;
4133   getCellsContainingPoint(pos,eps,elts);
4134   if(elts.empty())
4135     return -1;
4136   return elts.front();
4137 }
4138
4139 /*!
4140  * Finds cells in contact with a ball (i.e. a point with precision).
4141  * 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.
4142  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4143  * \warning This method is suitable if the caller intends to evaluate only one
4144  *          point, for more points getCellsContainingPoints() is recommended as it is
4145  *          faster.
4146  *  \param [in] pos - array of coordinates of the ball central point.
4147  *  \param [in] eps - ball radius.
4148  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4149  *         before inserting ids.
4150  *  \throw If the coordinates array is not set.
4151  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4152  *
4153  *  \if ENABLE_EXAMPLES
4154  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4155  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4156  *  \endif
4157  */
4158 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4159 {
4160   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4161   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4162   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4163 }
4164
4165 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4166                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4167                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4168 {
4169   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4170   if(spaceDim==3)
4171     {
4172       if(mDim==3)
4173         {
4174           const double *coords=_coords->getConstPointer();
4175           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4176         }
4177       else
4178         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4179     }
4180   else if(spaceDim==2)
4181     {
4182       if(mDim==2)
4183         {
4184           const double *coords=_coords->getConstPointer();
4185           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4186         }
4187       else
4188         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4189     }
4190   else if(spaceDim==1)
4191     {
4192       if(mDim==1)
4193         {
4194           const double *coords=_coords->getConstPointer();
4195           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4196         }
4197       else
4198         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4199     }
4200   else
4201     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4202 }
4203
4204 /*!
4205  * Finds cells in contact with several balls (i.e. points with precision).
4206  * This method is an extension of getCellContainingPoint() and
4207  * getCellsContainingPoint() for the case of multiple points.
4208  * 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.
4209  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4210  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4211  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4212  *         this->getSpaceDimension() * \a nbOfPoints
4213  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4214  *  \param [in] eps - radius of balls (i.e. the precision).
4215  *  \param [out] elts - vector returning ids of found cells.
4216  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4217  *         dividing cell ids in \a elts into groups each referring to one
4218  *         point. Its every element (except the last one) is an index pointing to the
4219  *         first id of a group of cells. For example cells in contact with the *i*-th
4220  *         point are described by following range of indices:
4221  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4222  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4223  *         Number of cells in contact with the *i*-th point is
4224  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4225  *  \throw If the coordinates array is not set.
4226  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4227  *
4228  *  \if ENABLE_EXAMPLES
4229  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4230  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4231  *  \endif
4232  */
4233 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4234                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4235 {
4236   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4237   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4238 }
4239
4240 /*!
4241  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4242  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4243  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4244  * 
4245  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4246  */
4247 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4248 {
4249   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4250   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4251 }
4252
4253 /*!
4254  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4255  * least two its edges intersect each other anywhere except their extremities. An
4256  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4257  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4258  *         cleared before filling in.
4259  *  \param [in] eps - precision.
4260  *  \throw If \a this->getMeshDimension() != 2.
4261  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4262  */
4263 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4264 {
4265   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4266   if(getMeshDimension()!=2)
4267     throw INTERP_KERNEL::Exception(msg);
4268   int spaceDim=getSpaceDimension();
4269   if(spaceDim!=2 && spaceDim!=3)
4270     throw INTERP_KERNEL::Exception(msg);
4271   const mcIdType *conn=_nodal_connec->getConstPointer();
4272   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4273   mcIdType nbOfCells=getNumberOfCells();
4274   std::vector<double> cell2DinS2;
4275   for(mcIdType i=0;i<nbOfCells;i++)
4276     {
4277       mcIdType offset=connI[i];
4278       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4279       if(nbOfNodesForCell<=3)
4280         continue;
4281       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4282       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4283       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4284         cells.push_back(i);
4285       cell2DinS2.clear();
4286     }
4287 }
4288
4289 /*!
4290  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4291  *
4292  * 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.
4293  * 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.
4294  *
4295  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4296  * This convex envelop is computed using Jarvis march algorithm.
4297  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4298  * 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)
4299  * 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.
4300  *
4301  * \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.
4302  * \sa MEDCouplingUMesh::colinearize2D
4303  */
4304 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4305 {
4306   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4307     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4308   checkFullyDefined();
4309   const double *coords=getCoords()->getConstPointer();
4310   mcIdType nbOfCells=getNumberOfCells();
4311   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4312   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4313   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4314   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4315   *workIndexOut=0;
4316   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4317   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4318   std::set<INTERP_KERNEL::NormalizedCellType> types;
4319   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4320   isChanged->alloc(0,1);
4321   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4322     {
4323       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4324       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4325         isChanged->pushBackSilent(i);
4326       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4327       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4328     }
4329   if(isChanged->empty())
4330     return 0;
4331   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4332   _types=types;
4333   return isChanged.retn();
4334 }
4335
4336 /*!
4337  * This method is \b NOT const because it can modify \a this.
4338  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4339  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4340  * \param policy specifies the type of extrusion chosen:
4341  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4342  *   will be repeated to build each level
4343  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4344  *   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
4345  *   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
4346  *   arc.
4347  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4348  */
4349 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4350 {
4351   checkFullyDefined();
4352   mesh1D->checkFullyDefined();
4353   if(!mesh1D->isContiguous1D())
4354     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4355   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4356     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4357   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4358     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4359   if(mesh1D->getMeshDimension()!=1)
4360     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4361   bool isQuad=false;
4362   if(isPresenceOfQuadratic())
4363     {
4364       if(mesh1D->isFullyQuadratic())
4365         isQuad=true;
4366       else
4367         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4368     }
4369   mcIdType oldNbOfNodes(getNumberOfNodes());
4370   MCAuto<DataArrayDouble> newCoords;
4371   switch(policy)
4372   {
4373     case 0:
4374       {
4375         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4376         break;
4377       }
4378     case 1:
4379       {
4380         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4381         break;
4382       }
4383     default:
4384       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4385   }
4386   setCoords(newCoords);
4387   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4388   updateTime();
4389   return ret.retn();
4390 }
4391
4392
4393 /*!
4394  * Checks if \a this mesh is constituted by only quadratic cells.
4395  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4396  *  \throw If the coordinates array is not set.
4397  *  \throw If the nodal connectivity of cells is not defined.
4398  */
4399 bool MEDCouplingUMesh::isFullyQuadratic() const
4400 {
4401   checkFullyDefined();
4402   bool ret=true;
4403   mcIdType nbOfCells=getNumberOfCells();
4404   for(mcIdType i=0;i<nbOfCells && ret;i++)
4405     {
4406       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4407       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4408       ret=cm.isQuadratic();
4409     }
4410   return ret;
4411 }
4412
4413 /*!
4414  * Checks if \a this mesh includes any quadratic cell.
4415  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4416  *  \throw If the coordinates array is not set.
4417  *  \throw If the nodal connectivity of cells is not defined.
4418  */
4419 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4420 {
4421   checkFullyDefined();
4422   bool ret=false;
4423   mcIdType nbOfCells=getNumberOfCells();
4424   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4425     {
4426       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4427       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4428       ret=cm.isQuadratic();
4429     }
4430   return ret;
4431 }
4432
4433 /*!
4434  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4435  * this mesh, it remains unchanged.
4436  *  \throw If the coordinates array is not set.
4437  *  \throw If the nodal connectivity of cells is not defined.
4438  */
4439 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4440 {
4441   checkFullyDefined();
4442   mcIdType nbOfCells=getNumberOfCells();
4443   mcIdType delta=0;
4444   const mcIdType *iciptr=_nodal_connec_index->begin();
4445   for(mcIdType i=0;i<nbOfCells;i++)
4446     {
4447       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4448       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4449       if(cm.isQuadratic())
4450         {
4451           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4452           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4453           if(!cml.isDynamic())
4454             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4455           else
4456             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4457         }
4458     }
4459   if(delta==0)
4460     return ;
4461   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4462   const mcIdType *icptr(_nodal_connec->begin());
4463   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4464   newConnI->alloc(nbOfCells+1,1);
4465   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4466   *ociptr=0;
4467   _types.clear();
4468   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4469     {
4470       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4471       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4472       if(!cm.isQuadratic())
4473         {
4474           _types.insert(type);
4475           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4476           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4477         }
4478       else
4479         {
4480           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4481           _types.insert(typel);
4482           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4483           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4484           if(cml.isDynamic())
4485             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4486           *ocptr++=ToIdType(typel);
4487           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4488           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4489         }
4490     }
4491   setConnectivity(newConn,newConnI,false);
4492 }
4493
4494 /*!
4495  * This method converts all linear cell in \a this to quadratic one.
4496  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4497  * 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)
4498  * 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.
4499  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4500  * end of the existing coordinates.
4501  *
4502  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4503  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4504  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4505  *
4506  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4507  *
4508  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4509  */
4510 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4511 {
4512   DataArrayIdType *conn=0,*connI=0;
4513   DataArrayDouble *coords=0;
4514   std::set<INTERP_KERNEL::NormalizedCellType> types;
4515   checkFullyDefined();
4516   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4517   MCAuto<DataArrayDouble> coordsSafe;
4518   int meshDim=getMeshDimension();
4519   switch(conversionType)
4520   {
4521     case 0:
4522       switch(meshDim)
4523       {
4524         case 1:
4525           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4526           connSafe=conn; connISafe=connI; coordsSafe=coords;
4527           break;
4528         case 2:
4529           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4530           connSafe=conn; connISafe=connI; coordsSafe=coords;
4531           break;
4532         case 3:
4533           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4534           connSafe=conn; connISafe=connI; coordsSafe=coords;
4535           break;
4536         default:
4537           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4538       }
4539       break;
4540         case 1:
4541           {
4542             switch(meshDim)
4543             {
4544               case 1:
4545                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4546                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4547                 break;
4548               case 2:
4549                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4550                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4551                 break;
4552               case 3:
4553                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4554                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4555                 break;
4556               default:
4557                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4558             }
4559             break;
4560           }
4561         default:
4562           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4563   }
4564   setConnectivity(connSafe,connISafe,false);
4565   _types=types;
4566   setCoords(coordsSafe);
4567   return ret.retn();
4568 }
4569
4570 /*!
4571  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4572  * so that the number of cells remains the same. Quadratic faces are converted to
4573  * polygons. This method works only for 2D meshes in
4574  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4575  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4576  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4577  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4578  *         a polylinized edge constituting the input polygon.
4579  *  \throw If the coordinates array is not set.
4580  *  \throw If the nodal connectivity of cells is not defined.
4581  *  \throw If \a this->getMeshDimension() != 2.
4582  *  \throw If \a this->getSpaceDimension() != 2.
4583  */
4584 void MEDCouplingUMesh::tessellate2D(double eps)
4585 {
4586   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4587   if(spaceDim!=2)
4588     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4589   switch(meshDim)
4590     {
4591     case 1:
4592       return tessellate2DCurveInternal(eps);
4593     case 2:
4594       return tessellate2DInternal(eps);
4595     default:
4596       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4597     }
4598 }
4599
4600 #if 0
4601 /*!
4602  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4603  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4604  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4605  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4606  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4607  * This method can be seen as the opposite method of colinearize2D.
4608  * 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
4609  * to avoid to modify the numbering of existing nodes.
4610  *
4611  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4612  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4613  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4614  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4615  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4616  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4617  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4618  *
4619  * \sa buildDescendingConnectivity2
4620  */
4621 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4622                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4623 {
4624   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4625     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4626   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4627   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4628     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4629   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4630     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4631   //DataArrayIdType *out0(0),*outi0(0);
4632   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4633   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4634   //out0s=out0s->buildUnique(); out0s->sort(true);
4635 }
4636 #endif
4637
4638
4639 /*!
4640  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4641  * In addition, returns an array mapping new cells to old ones. <br>
4642  * This method typically increases the number of cells in \a this mesh
4643  * but the number of nodes remains \b unchanged.
4644  * That's why the 3D splitting policies
4645  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4646  *  \param [in] policy - specifies a pattern used for splitting.
4647  * The semantic of \a policy is:
4648  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4649  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4650  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4651  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4652  *
4653  *
4654  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4655  *          an id of old cell producing it. The caller is to delete this array using
4656  *         decrRef() as it is no more needed.
4657  *
4658  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4659  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4660  *          and \a this->getMeshDimension() != 3.
4661  *  \throw If \a policy is not one of the four discussed above.
4662  *  \throw If the nodal connectivity of cells is not defined.
4663  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4664  */
4665 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4666 {
4667   switch(policy)
4668   {
4669     case 0:
4670       return simplexizePol0();
4671     case 1:
4672       return simplexizePol1();
4673     case INTERP_KERNEL::PLANAR_FACE_5:
4674         return simplexizePlanarFace5();
4675     case INTERP_KERNEL::PLANAR_FACE_6:
4676         return simplexizePlanarFace6();
4677     default:
4678       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)");
4679   }
4680 }
4681
4682 /*!
4683  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4684  * - 1D: INTERP_KERNEL::NORM_SEG2
4685  * - 2D: INTERP_KERNEL::NORM_TRI3
4686  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4687  *
4688  * This method is useful for users that need to use P1 field services as
4689  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4690  * All these methods need mesh support containing only simplex cells.
4691  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4692  *  \throw If the coordinates array is not set.
4693  *  \throw If the nodal connectivity of cells is not defined.
4694  *  \throw If \a this->getMeshDimension() < 1.
4695  */
4696 bool MEDCouplingUMesh::areOnlySimplexCells() const
4697 {
4698   checkFullyDefined();
4699   int mdim=getMeshDimension();
4700   if(mdim<1 || mdim>3)
4701     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4702   mcIdType nbCells=getNumberOfCells();
4703   const mcIdType *conn=_nodal_connec->begin();
4704   const mcIdType *connI=_nodal_connec_index->begin();
4705   for(mcIdType i=0;i<nbCells;i++)
4706     {
4707       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4708       if(!cm.isSimplex())
4709         return false;
4710     }
4711   return true;
4712 }
4713
4714
4715
4716 /*!
4717  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4718  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4719  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4720  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4721  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4722  * so it can be useful to call mergeNodes() before calling this method.
4723  *  \throw If \a this->getMeshDimension() <= 1.
4724  *  \throw If the coordinates array is not set.
4725  *  \throw If the nodal connectivity of cells is not defined.
4726  */
4727 void MEDCouplingUMesh::convertDegeneratedCells()
4728 {
4729   checkFullyDefined();
4730   if(getMeshDimension()<=1)
4731     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4732   mcIdType nbOfCells=getNumberOfCells();
4733   if(nbOfCells<1)
4734     return ;
4735   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4736   mcIdType *conn=_nodal_connec->getPointer();
4737   mcIdType *index=_nodal_connec_index->getPointer();
4738   mcIdType posOfCurCell=0;
4739   mcIdType newPos=0;
4740   mcIdType lgthOfCurCell;
4741   for(mcIdType i=0;i<nbOfCells;i++)
4742     {
4743       lgthOfCurCell=index[i+1]-posOfCurCell;
4744       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4745       mcIdType newLgth;
4746       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4747                                                                                                      conn+newPos+1,newLgth);
4748       conn[newPos]=newType;
4749       newPos+=newLgth+1;
4750       posOfCurCell=index[i+1];
4751       index[i+1]=newPos;
4752     }
4753   if(newPos!=initMeshLgth)
4754     _nodal_connec->reAlloc(newPos);
4755   computeTypes();
4756 }
4757
4758 /*!
4759  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4760  * A cell is flat in the following cases:
4761  *   - for a linear cell, all points in the connectivity are equal
4762  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4763  *   identical quadratic points
4764  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4765  *      this array using decrRef() as it is no more needed.
4766  */
4767 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4768 {
4769   checkFullyDefined();
4770   if(getMeshDimension()<=1)
4771     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4772   mcIdType nbOfCells=getNumberOfCells();
4773   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4774   if(nbOfCells<1)
4775     return ret.retn();
4776   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4777   mcIdType *conn=_nodal_connec->getPointer();
4778   mcIdType *index=_nodal_connec_index->getPointer();
4779   mcIdType posOfCurCell=0;
4780   mcIdType newPos=0;
4781   mcIdType lgthOfCurCell, nbDelCells(0);
4782   for(mcIdType i=0;i<nbOfCells;i++)
4783     {
4784       lgthOfCurCell=index[i+1]-posOfCurCell;
4785       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4786       mcIdType newLgth;
4787       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4788                                                                                                      conn+newPos+1,newLgth);
4789       // Shall we delete the cell if it is completely degenerated:
4790       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4791       if (delCell)
4792         {
4793           nbDelCells++;
4794           ret->pushBackSilent(i);
4795         }
4796       else   //if the cell is to be deleted, simply stay at the same place
4797         {
4798           conn[newPos]=newType;
4799           newPos+=newLgth+1;
4800         }
4801       posOfCurCell=index[i+1];
4802       index[i+1-nbDelCells]=newPos;
4803     }
4804   if(newPos!=initMeshLgth)
4805     _nodal_connec->reAlloc(newPos);
4806   const mcIdType nCellDel=ret->getNumberOfTuples();
4807   if (nCellDel)
4808     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4809   computeTypes();
4810   return ret.retn();
4811 }
4812
4813 /*!
4814  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4815  * Only connectivity is considered here.
4816  */
4817 bool MEDCouplingUMesh::removeDegenerated1DCells()
4818 {
4819   checkConnectivityFullyDefined();
4820   if(getMeshDimension()!=1)
4821     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4822   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4823   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4824   {
4825     for(std::size_t i=0;i<nbCells;i++)
4826       {
4827         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4828         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4829           {
4830             if(conn[conni[i]+1]!=conn[conni[i]+2])
4831               {
4832                 newSize++;
4833                 newSize2+=conni[i+1]-conni[i];
4834               }
4835           }
4836         else
4837           {
4838             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4839             throw INTERP_KERNEL::Exception(oss.str());
4840           }
4841       }
4842   }
4843   if(newSize==nbCells)//no cells has been removed -> do nothing
4844     return false;
4845   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4846   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4847   for(std::size_t i=0;i<nbCells;i++)
4848     {
4849       if(conn[conni[i]+1]!=conn[conni[i]+2])
4850         {
4851           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4852           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4853           newConnIPtr++;
4854         }
4855     }
4856   setConnectivity(newConn,newConnI,true);
4857   return true;
4858 }
4859
4860 /*!
4861  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4862  * A cell is considered to be oriented correctly if an angle between its
4863  * normal vector and a given vector is less than \c PI / \c 2.
4864  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4865  *         cells.
4866  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4867  *         checked.
4868  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4869  *         is not cleared before filling in.
4870  *  \throw If \a this->getMeshDimension() != 2.
4871  *  \throw If \a this->getSpaceDimension() != 3.
4872  *
4873  *  \if ENABLE_EXAMPLES
4874  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4875  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4876  *  \endif
4877  */
4878 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4879 {
4880   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4881     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4882   mcIdType nbOfCells=getNumberOfCells();
4883   const mcIdType *conn=_nodal_connec->begin();
4884   const mcIdType *connI=_nodal_connec_index->begin();
4885   const double *coordsPtr=_coords->begin();
4886   for(mcIdType i=0;i<nbOfCells;i++)
4887     {
4888       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4889       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4890         {
4891           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4892           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4893             cells.push_back(i);
4894         }
4895     }
4896 }
4897
4898 /*!
4899  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4900  * considered to be oriented correctly if an angle between its normal vector and a
4901  * given vector is less than \c PI / \c 2.
4902  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4903  *         cells.
4904  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4905  *         checked.
4906  *  \throw If \a this->getMeshDimension() != 2.
4907  *  \throw If \a this->getSpaceDimension() != 3.
4908  *
4909  *  \if ENABLE_EXAMPLES
4910  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4911  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4912  *  \endif
4913  *
4914  *  \sa changeOrientationOfCells
4915  */
4916 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4917 {
4918   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4919     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4920   mcIdType nbOfCells=getNumberOfCells();
4921   mcIdType *conn(_nodal_connec->getPointer());
4922   const mcIdType *connI(_nodal_connec_index->begin());
4923   const double *coordsPtr(_coords->begin());
4924   bool isModified(false);
4925   for(mcIdType i=0;i<nbOfCells;i++)
4926     {
4927       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4928       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4929         {
4930           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4931           bool isQuadratic(cm.isQuadratic());
4932           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4933             {
4934               isModified=true;
4935               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4936             }
4937         }
4938     }
4939   if(isModified)
4940     _nodal_connec->declareAsNew();
4941   updateTime();
4942 }
4943
4944 /*!
4945  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4946  *
4947  * \sa orientCorrectly2DCells
4948  */
4949 void MEDCouplingUMesh::changeOrientationOfCells()
4950 {
4951   int mdim(getMeshDimension());
4952   if(mdim!=2 && mdim!=1)
4953     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4954   mcIdType nbOfCells=getNumberOfCells();
4955   mcIdType *conn(_nodal_connec->getPointer());
4956   const mcIdType *connI(_nodal_connec_index->begin());
4957   if(mdim==2)
4958     {//2D
4959       for(mcIdType i=0;i<nbOfCells;i++)
4960         {
4961           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4962           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4963           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4964         }
4965     }
4966   else
4967     {//1D
4968       for(mcIdType i=0;i<nbOfCells;i++)
4969         {
4970           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4971           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4972           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4973         }
4974     }
4975 }
4976
4977 /*!
4978  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4979  * oriented facets. The normal vector of the facet should point out of the cell.
4980  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4981  *         is not cleared before filling in.
4982  *  \throw If \a this->getMeshDimension() != 3.
4983  *  \throw If \a this->getSpaceDimension() != 3.
4984  *  \throw If the coordinates array is not set.
4985  *  \throw If the nodal connectivity of cells is not defined.
4986  *
4987  *  \if ENABLE_EXAMPLES
4988  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4989  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4990  *  \endif
4991  */
4992 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4993 {
4994   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4995     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4996   mcIdType nbOfCells=getNumberOfCells();
4997   const mcIdType *conn=_nodal_connec->begin();
4998   const mcIdType *connI=_nodal_connec_index->begin();
4999   const double *coordsPtr=_coords->begin();
5000   for(mcIdType i=0;i<nbOfCells;i++)
5001     {
5002       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5003       if(type==INTERP_KERNEL::NORM_POLYHED)
5004         {
5005           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5006             cells.push_back(i);
5007         }
5008     }
5009 }
5010
5011 /*!
5012  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5013  * out of the cell.
5014  *  \throw If \a this->getMeshDimension() != 3.
5015  *  \throw If \a this->getSpaceDimension() != 3.
5016  *  \throw If the coordinates array is not set.
5017  *  \throw If the nodal connectivity of cells is not defined.
5018  *  \throw If the reparation fails.
5019  *
5020  *  \if ENABLE_EXAMPLES
5021  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5022  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5023  *  \endif
5024  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5025  */
5026 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5027 {
5028   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5029     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5030   mcIdType nbOfCells=getNumberOfCells();
5031   mcIdType *conn=_nodal_connec->getPointer();
5032   const mcIdType *connI=_nodal_connec_index->begin();
5033   const double *coordsPtr=_coords->begin();
5034   for(mcIdType i=0;i<nbOfCells;i++)
5035     {
5036       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5037       if(type==INTERP_KERNEL::NORM_POLYHED)
5038         {
5039           try
5040           {
5041               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5042                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5043           }
5044           catch(INTERP_KERNEL::Exception& e)
5045           {
5046               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5047               throw INTERP_KERNEL::Exception(oss.str());
5048           }
5049         }
5050     }
5051   updateTime();
5052 }
5053
5054 /*!
5055  * This method invert orientation of all cells in \a this.
5056  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5057  * This method only operates on the connectivity so coordinates are not touched at all.
5058  */
5059 void MEDCouplingUMesh::invertOrientationOfAllCells()
5060 {
5061   checkConnectivityFullyDefined();
5062   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5063   mcIdType *conn(_nodal_connec->getPointer());
5064   const mcIdType *conni(_nodal_connec_index->begin());
5065   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5066     {
5067       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5068       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5069       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5070         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5071     }
5072   updateTime();
5073 }
5074
5075 /*!
5076  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5077  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5078  * according to which the first facet of the cell should be oriented to have the normal vector
5079  * pointing out of cell.
5080  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5081  *         cells. The caller is to delete this array using decrRef() as it is no more
5082  *         needed.
5083  *  \throw If \a this->getMeshDimension() != 3.
5084  *  \throw If \a this->getSpaceDimension() != 3.
5085  *  \throw If the coordinates array is not set.
5086  *  \throw If the nodal connectivity of cells is not defined.
5087  *
5088  *  \if ENABLE_EXAMPLES
5089  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5090  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5091  *  \endif
5092  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5093  */
5094 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5095 {
5096   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5097   if(getMeshDimension()!=3)
5098     throw INTERP_KERNEL::Exception(msg);
5099   int spaceDim=getSpaceDimension();
5100   if(spaceDim!=3)
5101     throw INTERP_KERNEL::Exception(msg);
5102   //
5103   mcIdType nbOfCells=getNumberOfCells();
5104   mcIdType *conn=_nodal_connec->getPointer();
5105   const mcIdType *connI=_nodal_connec_index->begin();
5106   const double *coo=getCoords()->begin();
5107   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5108   for(mcIdType i=0;i<nbOfCells;i++)
5109     {
5110       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5111       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5112         {
5113           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5114             {
5115               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5116               cells->pushBackSilent(i);
5117             }
5118         }
5119     }
5120   return cells.retn();
5121 }
5122
5123 /*!
5124  * This method is a faster method to correct orientation of all 3D cells in \a this.
5125  * 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.
5126  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5127  *
5128  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5129  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5130  */
5131 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5132 {
5133   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5134     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5135   mcIdType nbOfCells=getNumberOfCells();
5136   mcIdType *conn=_nodal_connec->getPointer();
5137   const mcIdType *connI=_nodal_connec_index->begin();
5138   const double *coordsPtr=_coords->begin();
5139   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5140   for(mcIdType i=0;i<nbOfCells;i++)
5141     {
5142       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5143       switch(type)
5144       {
5145         case INTERP_KERNEL::NORM_TETRA4:
5146           {
5147             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5148               {
5149                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5150                 ret->pushBackSilent(i);
5151               }
5152             break;
5153           }
5154         case INTERP_KERNEL::NORM_PYRA5:
5155           {
5156             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5157               {
5158                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5159                 ret->pushBackSilent(i);
5160               }
5161             break;
5162           }
5163         case INTERP_KERNEL::NORM_PENTA6:
5164         case INTERP_KERNEL::NORM_HEXA8:
5165         case INTERP_KERNEL::NORM_HEXGP12:
5166           {
5167             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5168               {
5169                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5170                 ret->pushBackSilent(i);
5171               }
5172             break;
5173           }
5174         case INTERP_KERNEL::NORM_POLYHED:
5175           {
5176             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5177               {
5178                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5179                 ret->pushBackSilent(i);
5180               }
5181             break;
5182           }
5183         default:
5184           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 !");
5185       }
5186     }
5187   updateTime();
5188   return ret.retn();
5189 }
5190
5191 /*!
5192  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5193  * If it is not the case an exception will be thrown.
5194  * This method is fast because the first cell of \a this is used to compute the plane.
5195  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5196  * \param pos output of size at least 3 used to store a point owned of searched plane.
5197  */
5198 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5199 {
5200   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5201     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5202   const mcIdType *conn=_nodal_connec->begin();
5203   const mcIdType *connI=_nodal_connec_index->begin();
5204   const double *coordsPtr=_coords->begin();
5205   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5206   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5207 }
5208
5209 /*!
5210  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5211  * cells. Currently cells of the following types are treated:
5212  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5213  * For a cell of other type an exception is thrown.
5214  * Space dimension of a 2D mesh can be either 2 or 3.
5215  * The Edge Ratio of a cell \f$t\f$ is:
5216  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5217  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5218  *  the smallest edge lengths of \f$t\f$.
5219  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5220  *          cells and one time, lying on \a this mesh. The caller is to delete this
5221  *          field using decrRef() as it is no more needed.
5222  *  \throw If the coordinates array is not set.
5223  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5224  *  \throw If the connectivity data array has more than one component.
5225  *  \throw If the connectivity data array has a named component.
5226  *  \throw If the connectivity index data array has more than one component.
5227  *  \throw If the connectivity index data array has a named component.
5228  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5229  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5230  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5231  */
5232 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5233 {
5234   checkConsistencyLight();
5235   int spaceDim=getSpaceDimension();
5236   int meshDim=getMeshDimension();
5237   if(spaceDim!=2 && spaceDim!=3)
5238     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5239   if(meshDim!=2 && meshDim!=3)
5240     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5241   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5242   ret->setMesh(this);
5243   mcIdType nbOfCells=getNumberOfCells();
5244   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5245   arr->alloc(nbOfCells,1);
5246   double *pt=arr->getPointer();
5247   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5248   const mcIdType *conn=_nodal_connec->begin();
5249   const mcIdType *connI=_nodal_connec_index->begin();
5250   const double *coo=_coords->begin();
5251   double tmp[12];
5252   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5253     {
5254       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5255       switch(t)
5256       {
5257         case INTERP_KERNEL::NORM_TRI3:
5258           {
5259             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5260             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5261             break;
5262           }
5263         case INTERP_KERNEL::NORM_QUAD4:
5264           {
5265             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5266             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5267             break;
5268           }
5269         case INTERP_KERNEL::NORM_TETRA4:
5270           {
5271             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5272             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5273             break;
5274           }
5275         default:
5276           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5277       }
5278       conn+=connI[i+1]-connI[i];
5279     }
5280   ret->setName("EdgeRatio");
5281   ret->synchronizeTimeWithSupport();
5282   return ret.retn();
5283 }
5284
5285 /*!
5286  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5287  * cells. Currently cells of the following types are treated:
5288  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5289  * For a cell of other type an exception is thrown.
5290  * Space dimension of a 2D mesh can be either 2 or 3.
5291  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5292  *          cells and one time, lying on \a this mesh. The caller is to delete this
5293  *          field using decrRef() as it is no more needed.
5294  *  \throw If the coordinates array is not set.
5295  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5296  *  \throw If the connectivity data array has more than one component.
5297  *  \throw If the connectivity data array has a named component.
5298  *  \throw If the connectivity index data array has more than one component.
5299  *  \throw If the connectivity index data array has a named component.
5300  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5301  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5302  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5303  */
5304 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5305 {
5306   checkConsistencyLight();
5307   int spaceDim=getSpaceDimension();
5308   int meshDim=getMeshDimension();
5309   if(spaceDim!=2 && spaceDim!=3)
5310     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5311   if(meshDim!=2 && meshDim!=3)
5312     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5313   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5314   ret->setMesh(this);
5315   mcIdType nbOfCells=getNumberOfCells();
5316   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5317   arr->alloc(nbOfCells,1);
5318   double *pt=arr->getPointer();
5319   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5320   const mcIdType *conn=_nodal_connec->begin();
5321   const mcIdType *connI=_nodal_connec_index->begin();
5322   const double *coo=_coords->begin();
5323   double tmp[12];
5324   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5325     {
5326       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5327       switch(t)
5328       {
5329         case INTERP_KERNEL::NORM_TRI3:
5330           {
5331             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5332             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5333             break;
5334           }
5335         case INTERP_KERNEL::NORM_QUAD4:
5336           {
5337             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5338             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5339             break;
5340           }
5341         case INTERP_KERNEL::NORM_TETRA4:
5342           {
5343             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5344             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5345             break;
5346           }
5347         default:
5348           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5349       }
5350       conn+=connI[i+1]-connI[i];
5351     }
5352   ret->setName("AspectRatio");
5353   ret->synchronizeTimeWithSupport();
5354   return ret.retn();
5355 }
5356
5357 /*!
5358  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5359  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5360  * in 3D space. Currently only cells of the following types are
5361  * treated: INTERP_KERNEL::NORM_QUAD4.
5362  * For a cell of other type an exception is thrown.
5363  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5364  * Defining
5365  * \f$t=\vec{da}\times\vec{ab}\f$,
5366  * \f$u=\vec{ab}\times\vec{bc}\f$
5367  * \f$v=\vec{bc}\times\vec{cd}\f$
5368  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5369  *  \f[
5370  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5371  *  \f]
5372  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5373  *          cells and one time, lying on \a this mesh. The caller is to delete this
5374  *          field using decrRef() as it is no more needed.
5375  *  \throw If the coordinates array is not set.
5376  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5377  *  \throw If the connectivity data array has more than one component.
5378  *  \throw If the connectivity data array has a named component.
5379  *  \throw If the connectivity index data array has more than one component.
5380  *  \throw If the connectivity index data array has a named component.
5381  *  \throw If \a this->getMeshDimension() != 2.
5382  *  \throw If \a this->getSpaceDimension() != 3.
5383  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5384  */
5385 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5386 {
5387   checkConsistencyLight();
5388   int spaceDim=getSpaceDimension();
5389   int meshDim=getMeshDimension();
5390   if(spaceDim!=3)
5391     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5392   if(meshDim!=2)
5393     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5394   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5395   ret->setMesh(this);
5396   mcIdType nbOfCells=getNumberOfCells();
5397   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5398   arr->alloc(nbOfCells,1);
5399   double *pt=arr->getPointer();
5400   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5401   const mcIdType *conn=_nodal_connec->begin();
5402   const mcIdType *connI=_nodal_connec_index->begin();
5403   const double *coo=_coords->begin();
5404   double tmp[12];
5405   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5406     {
5407       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5408       switch(t)
5409       {
5410         case INTERP_KERNEL::NORM_QUAD4:
5411           {
5412             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5413             *pt=INTERP_KERNEL::quadWarp(tmp);
5414             break;
5415           }
5416         default:
5417           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5418       }
5419       conn+=connI[i+1]-connI[i];
5420     }
5421   ret->setName("Warp");
5422   ret->synchronizeTimeWithSupport();
5423   return ret.retn();
5424 }
5425
5426
5427 /*!
5428  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5429  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5430  * treated: INTERP_KERNEL::NORM_QUAD4.
5431  * The skew is computed as follow for a quad with points (a,b,c,d): let
5432  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5433  * then the skew is computed as:
5434  *  \f[
5435  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5436  *  \f]
5437  *
5438  * For a cell of other type an exception is thrown.
5439  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5440  *          cells and one time, lying on \a this mesh. The caller is to delete this
5441  *          field using decrRef() as it is no more needed.
5442  *  \throw If the coordinates array is not set.
5443  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5444  *  \throw If the connectivity data array has more than one component.
5445  *  \throw If the connectivity data array has a named component.
5446  *  \throw If the connectivity index data array has more than one component.
5447  *  \throw If the connectivity index data array has a named component.
5448  *  \throw If \a this->getMeshDimension() != 2.
5449  *  \throw If \a this->getSpaceDimension() != 3.
5450  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5451  */
5452 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5453 {
5454   checkConsistencyLight();
5455   int spaceDim=getSpaceDimension();
5456   int meshDim=getMeshDimension();
5457   if(spaceDim!=3)
5458     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5459   if(meshDim!=2)
5460     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5461   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5462   ret->setMesh(this);
5463   mcIdType nbOfCells=getNumberOfCells();
5464   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5465   arr->alloc(nbOfCells,1);
5466   double *pt=arr->getPointer();
5467   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5468   const mcIdType *conn=_nodal_connec->begin();
5469   const mcIdType *connI=_nodal_connec_index->begin();
5470   const double *coo=_coords->begin();
5471   double tmp[12];
5472   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5473     {
5474       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5475       switch(t)
5476       {
5477         case INTERP_KERNEL::NORM_QUAD4:
5478           {
5479             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5480             *pt=INTERP_KERNEL::quadSkew(tmp);
5481             break;
5482           }
5483         default:
5484           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5485       }
5486       conn+=connI[i+1]-connI[i];
5487     }
5488   ret->setName("Skew");
5489   ret->synchronizeTimeWithSupport();
5490   return ret.retn();
5491 }
5492
5493 /*!
5494  * 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.
5495  *
5496  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5497  *
5498  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5499  */
5500 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5501 {
5502   checkConsistencyLight();
5503   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5504   ret->setMesh(this);
5505   std::set<INTERP_KERNEL::NormalizedCellType> types;
5506   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5507   int spaceDim(getSpaceDimension());
5508   mcIdType nbCells(getNumberOfCells());
5509   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5510   arr->alloc(nbCells,1);
5511   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5512     {
5513       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5514       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5515       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5516     }
5517   ret->setArray(arr);
5518   ret->setName("Diameter");
5519   return ret.retn();
5520 }
5521
5522 /*!
5523  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5524  *
5525  * \param [in] arcDetEps - a parameter specifying in case of 2D quadratic polygon cell the detection limit between linear and arc circle. (By default 1e-12)
5526  *                         For all other cases this input parameter is ignored.
5527  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5528  *
5529  * \throw If \a this is not fully set (coordinates and connectivity).
5530  * \throw If a cell in \a this has no valid nodeId.
5531  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5532  */
5533 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5534 {
5535   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5536   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.
5537     return getBoundingBoxForBBTreeFast();
5538   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5539     {
5540       bool presenceOfQuadratic(false);
5541       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5542         {
5543           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5544           if(cm.isQuadratic())
5545             presenceOfQuadratic=true;
5546         }
5547       if(!presenceOfQuadratic)
5548         return getBoundingBoxForBBTreeFast();
5549       if(mDim==2 && sDim==2)
5550         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5551       else
5552         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5553     }
5554   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) !");
5555 }
5556
5557 /*!
5558  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5559  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5560  *
5561  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5562  *
5563  * \throw If \a this is not fully set (coordinates and connectivity).
5564  * \throw If a cell in \a this has no valid nodeId.
5565  */
5566 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5567 {
5568   checkFullyDefined();
5569   int spaceDim(getSpaceDimension());
5570   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5571   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5572   double *bbox(ret->getPointer());
5573   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5574     {
5575       bbox[2*i]=std::numeric_limits<double>::max();
5576       bbox[2*i+1]=-std::numeric_limits<double>::max();
5577     }
5578   const double *coordsPtr(_coords->begin());
5579   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5580   for(mcIdType i=0;i<nbOfCells;i++)
5581     {
5582       mcIdType offset=connI[i]+1;
5583       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5584       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5585         {
5586           mcIdType nodeId=conn[offset+j];
5587           if(nodeId>=0 && nodeId<nbOfNodes)
5588             {
5589               for(int k=0;k<spaceDim;k++)
5590                 {
5591                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5592                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5593                 }
5594               kk++;
5595             }
5596         }
5597       if(kk==0)
5598         {
5599           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5600           throw INTERP_KERNEL::Exception(oss.str());
5601         }
5602     }
5603   return ret.retn();
5604 }
5605
5606 /*!
5607  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5608  * useful for 2D meshes having quadratic cells
5609  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5610  * the two extremities of the arc of circle).
5611  *
5612  * \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)
5613  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5614  * \throw If \a this is not fully defined.
5615  * \throw If \a this is not a mesh with meshDimension equal to 2.
5616  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5617  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5618  */
5619 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5620 {
5621   checkFullyDefined();
5622   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5623
5624   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5625   mcIdType nbOfCells=getNumberOfCells();
5626   if(spaceDim!=2 || mDim!=2)
5627     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!");
5628   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5629   double *bbox(ret->getPointer());
5630   const double *coords(_coords->begin());
5631   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5632   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5633     {
5634       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5635       mcIdType sz(connI[1]-connI[0]-1);
5636       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5637       INTERP_KERNEL::QuadraticPolygon *pol(0);
5638       for(mcIdType j=0;j<sz;j++)
5639         {
5640           mcIdType nodeId(conn[*connI+1+j]);
5641           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5642         }
5643       if(!cm.isQuadratic())
5644         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5645       else
5646         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5647       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5648       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5649     }
5650   return ret.retn();
5651 }
5652
5653 /*!
5654  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5655  * useful for 2D meshes having quadratic cells
5656  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5657  * the two extremities of the arc of circle).
5658  *
5659  * \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)
5660  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5661  * \throw If \a this is not fully defined.
5662  * \throw If \a this is not a mesh with meshDimension equal to 1.
5663  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5664  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5665  */
5666 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5667 {
5668   checkFullyDefined();
5669   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5670   mcIdType nbOfCells=getNumberOfCells();
5671   if(spaceDim!=2 || mDim!=1)
5672     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!");
5673   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5674   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5675   double *bbox(ret->getPointer());
5676   const double *coords(_coords->begin());
5677   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5678   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5679     {
5680       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5681       mcIdType sz(connI[1]-connI[0]-1);
5682       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5683       INTERP_KERNEL::Edge *edge(0);
5684       for(mcIdType j=0;j<sz;j++)
5685         {
5686           mcIdType nodeId(conn[*connI+1+j]);
5687           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5688         }
5689       if(!cm.isQuadratic())
5690         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5691       else
5692         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5693       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5694       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5695     }
5696   return ret.retn();
5697 }
5698
5699 /// @cond INTERNAL
5700
5701 namespace MEDCouplingImpl
5702 {
5703   class ConnReader
5704   {
5705   public:
5706     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5707     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5708   private:
5709     const mcIdType *_conn;
5710     mcIdType _val;
5711   };
5712
5713   class ConnReader2
5714   {
5715   public:
5716     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5717     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5718   private:
5719     const mcIdType *_conn;
5720     mcIdType _val;
5721   };
5722 }
5723
5724 /// @endcond
5725
5726 /*!
5727  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5728  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5729  * \a this is composed in cell types.
5730  * The returned array is of size 3*n where n is the number of different types present in \a this.
5731  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5732  * This parameter is kept only for compatibility with other method listed above.
5733  */
5734 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5735 {
5736   checkConnectivityFullyDefined();
5737   const mcIdType *conn=_nodal_connec->begin();
5738   const mcIdType *connI=_nodal_connec_index->begin();
5739   const mcIdType *work=connI;
5740   mcIdType nbOfCells=getNumberOfCells();
5741   std::size_t n=getAllGeoTypes().size();
5742   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5743   std::set<INTERP_KERNEL::NormalizedCellType> types;
5744   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5745     {
5746       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5747       if(types.find(typ)!=types.end())
5748         {
5749           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5750           oss << " is not contiguous !";
5751           throw INTERP_KERNEL::Exception(oss.str());
5752         }
5753       types.insert(typ);
5754       ret[3*i]=typ;
5755       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5756       ret[3*i+1]=ToIdType(std::distance(work,work2));
5757       work=work2;
5758     }
5759   return ret;
5760 }
5761
5762 /*!
5763  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5764  * only for types cell, type node is not managed.
5765  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5766  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5767  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5768  * If 2 or more same geometric type is in \a code and exception is thrown too.
5769  *
5770  * This method firstly checks
5771  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5772  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5773  * an exception is thrown too.
5774  *
5775  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5776  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5777  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5778  */
5779 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5780 {
5781   if(code.empty())
5782     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5783   std::size_t sz=code.size();
5784   std::size_t n=sz/3;
5785   if(sz%3!=0)
5786     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5787   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5788   mcIdType nb=0;
5789   bool isNoPflUsed=true;
5790   for(std::size_t i=0;i<n;i++)
5791     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5792       {
5793         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5794         nb+=code[3*i+1];
5795         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5796           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5797         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5798       }
5799   if(types.size()!=n)
5800     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5801   if(isNoPflUsed)
5802     {
5803       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5804         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5805       if(types.size()==_types.size())
5806         return 0;
5807     }
5808   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5809   ret->alloc(nb,1);
5810   mcIdType *retPtr=ret->getPointer();
5811   const mcIdType *connI=_nodal_connec_index->begin();
5812   const mcIdType *conn=_nodal_connec->begin();
5813   mcIdType nbOfCells=getNumberOfCells();
5814   const mcIdType *i=connI;
5815   int kk=0;
5816   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5817     {
5818       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5819       mcIdType offset=ToIdType(std::distance(connI,i));
5820       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5821       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5822       if(code[3*kk+2]==-1)
5823         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5824           *retPtr++=k+offset;
5825       else
5826         {
5827           mcIdType idInIdsPerType=code[3*kk+2];
5828           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5829             {
5830               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5831               if(zePfl)
5832                 {
5833                   zePfl->checkAllocated();
5834                   if(zePfl->getNumberOfComponents()==1)
5835                     {
5836                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5837                         {
5838                           if(*k>=0 && *k<nbOfCellsOfCurType)
5839                             *retPtr=(*k)+offset;
5840                           else
5841                             {
5842                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5843                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5844                               throw INTERP_KERNEL::Exception(oss.str());
5845                             }
5846                         }
5847                     }
5848                   else
5849                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5850                 }
5851               else
5852                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5853             }
5854           else
5855             {
5856               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5857               oss << " should be in [0," << idsPerType.size() << ") !";
5858               throw INTERP_KERNEL::Exception(oss.str());
5859             }
5860         }
5861       i=j;
5862     }
5863   return ret.retn();
5864 }
5865
5866 /*!
5867  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5868  * 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.
5869  * 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.
5870  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5871  *
5872  * \param [in] profile list of IDs constituing the profile
5873  * \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.
5874  * \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,
5875  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5876  * \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.
5877  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5878  * \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
5879  */
5880 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5881 {
5882   if(!profile)
5883     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5884   if(profile->getNumberOfComponents()!=1)
5885     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5886   checkConnectivityFullyDefined();
5887   const mcIdType *conn=_nodal_connec->begin();
5888   const mcIdType *connI=_nodal_connec_index->begin();
5889   mcIdType nbOfCells=getNumberOfCells();
5890   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5891   std::vector<mcIdType> typeRangeVals(1);
5892   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5893     {
5894       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5895       if(std::find(types.begin(),types.end(),curType)!=types.end())
5896         {
5897           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5898         }
5899       types.push_back(curType);
5900       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5901       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5902     }
5903   //
5904   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5905   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5906   MCAuto<DataArrayIdType> tmp0=castArr;
5907   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5908   MCAuto<DataArrayIdType> tmp2=castsPresent;
5909   //
5910   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5911   code.resize(3*nbOfCastsFinal);
5912   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5913   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5914   for(mcIdType i=0;i<nbOfCastsFinal;i++)
5915     {
5916       mcIdType castId=castsPresent->getIJ(i,0);
5917       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5918       idsInPflPerType2.push_back(tmp3);
5919       code[3*i]=ToIdType(types[castId]);
5920       code[3*i+1]=tmp3->getNumberOfTuples();
5921       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5922       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5923         {
5924           tmp4->copyStringInfoFrom(*profile);
5925           idsPerType2.push_back(tmp4);
5926           code[3*i+2]=ToIdType(idsPerType2.size())-1;
5927         }
5928       else
5929         {
5930           code[3*i+2]=-1;
5931         }
5932     }
5933   std::size_t sz2=idsInPflPerType2.size();
5934   idsInPflPerType.resize(sz2);
5935   for(std::size_t i=0;i<sz2;i++)
5936     {
5937       DataArrayIdType *locDa=idsInPflPerType2[i];
5938       locDa->incrRef();
5939       idsInPflPerType[i]=locDa;
5940     }
5941   std::size_t sz=idsPerType2.size();
5942   idsPerType.resize(sz);
5943   for(std::size_t i=0;i<sz;i++)
5944     {
5945       DataArrayIdType *locDa=idsPerType2[i];
5946       locDa->incrRef();
5947       idsPerType[i]=locDa;
5948     }
5949 }
5950
5951 /*!
5952  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5953  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5954  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5955  * 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.
5956  */
5957 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5958 {
5959   checkFullyDefined();
5960   nM1LevMesh->checkFullyDefined();
5961   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5962     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5963   if(_coords!=nM1LevMesh->getCoords())
5964     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5965   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5966   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5967   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5968   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5969   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5970   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5971   tmp->setConnectivity(tmp0,tmp1);
5972   tmp->renumberCells(ret0->begin(),false);
5973   revDesc=tmp->getNodalConnectivity();
5974   revDescIndx=tmp->getNodalConnectivityIndex();
5975   DataArrayIdType *ret=0;
5976   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5977     {
5978       mcIdType tmp2;
5979       ret->getMaxValue(tmp2);
5980       ret->decrRef();
5981       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5982       throw INTERP_KERNEL::Exception(oss.str());
5983     }
5984   nM1LevMeshIds=ret;
5985   //
5986   revDesc->incrRef();
5987   revDescIndx->incrRef();
5988   ret1->incrRef();
5989   ret0->incrRef();
5990   meshnM1Old2New=ret0;
5991   return ret1;
5992 }
5993
5994 /*!
5995  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5996  * necessary for writing the mesh to MED file. Additionally returns a permutation array
5997  * in "Old to New" mode.
5998  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5999  *          this array using decrRef() as it is no more needed.
6000  *  \throw If the nodal connectivity of cells is not defined.
6001  */
6002 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6003 {
6004   checkConnectivityFullyDefined();
6005   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6006   renumberCells(ret->begin(),false);
6007   return ret.retn();
6008 }
6009
6010 /*!
6011  * This methods checks that cells are sorted by their types.
6012  * This method makes asumption (no check) that connectivity is correctly set before calling.
6013  */
6014 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6015 {
6016   checkFullyDefined();
6017   const mcIdType *conn=_nodal_connec->begin();
6018   const mcIdType *connI=_nodal_connec_index->begin();
6019   mcIdType nbOfCells=getNumberOfCells();
6020   std::set<INTERP_KERNEL::NormalizedCellType> types;
6021   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6022     {
6023       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6024       if(types.find(curType)!=types.end())
6025         return false;
6026       types.insert(curType);
6027       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6028     }
6029   return true;
6030 }
6031
6032 /*!
6033  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6034  * The geometric type order is specified by MED file.
6035  *
6036  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6037  */
6038 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6039 {
6040   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6041 }
6042
6043 /*!
6044  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6045  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6046  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6047  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6048  */
6049 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6050 {
6051   checkFullyDefined();
6052   const mcIdType *conn=_nodal_connec->begin();
6053   const mcIdType *connI=_nodal_connec_index->begin();
6054   mcIdType nbOfCells=getNumberOfCells();
6055   if(nbOfCells==0)
6056     return true;
6057   mcIdType lastPos=-1;
6058   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6059   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6060     {
6061       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6062       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6063       if(isTypeExists!=orderEnd)
6064         {
6065           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6066           if(pos<=lastPos)
6067             return false;
6068           lastPos=pos;
6069           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6070         }
6071       else
6072         {
6073           if(sg.find(curType)==sg.end())
6074             {
6075               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6076               sg.insert(curType);
6077             }
6078           else
6079             return false;
6080         }
6081     }
6082   return true;
6083 }
6084
6085 /*!
6086  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6087  * 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
6088  * 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'.
6089  */
6090 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6091 {
6092   checkConnectivityFullyDefined();
6093   mcIdType nbOfCells=getNumberOfCells();
6094   const mcIdType *conn=_nodal_connec->begin();
6095   const mcIdType *connI=_nodal_connec_index->begin();
6096   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6097   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6098   tmpa->alloc(nbOfCells,1);
6099   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6100   tmpb->fillWithZero();
6101   mcIdType *tmp=tmpa->getPointer();
6102   mcIdType *tmp2=tmpb->getPointer();
6103   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6104     {
6105       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6106       if(where!=orderEnd)
6107         {
6108           mcIdType pos=ToIdType(std::distance(orderBg,where));
6109           tmp2[pos]++;
6110           tmp[std::distance(connI,i)]=pos;
6111         }
6112       else
6113         {
6114           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6115           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6116           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6117           throw INTERP_KERNEL::Exception(oss.str());
6118         }
6119     }
6120   nbPerType=tmpb.retn();
6121   return tmpa.retn();
6122 }
6123
6124 /*!
6125  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6126  *
6127  * \return a new object containing the old to new correspondence.
6128  *
6129  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6130  */
6131 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6132 {
6133   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6134 }
6135
6136 /*!
6137  * 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.
6138  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6139  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6140  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6141  */
6142 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6143 {
6144   DataArrayIdType *nbPerType=0;
6145   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6146   nbPerType->decrRef();
6147   return tmpa->buildPermArrPerLevel();
6148 }
6149
6150 /*!
6151  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6152  * The number of cells remains unchanged after the call of this method.
6153  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6154  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6155  *
6156  * \return the array giving the correspondence old to new.
6157  */
6158 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6159 {
6160   checkFullyDefined();
6161   computeTypes();
6162   const mcIdType *conn=_nodal_connec->begin();
6163   const mcIdType *connI=_nodal_connec_index->begin();
6164   mcIdType nbOfCells=getNumberOfCells();
6165   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6166   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6167     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6168       {
6169         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6170         types.push_back(curType);
6171         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6172       }
6173   DataArrayIdType *ret=DataArrayIdType::New();
6174   ret->alloc(nbOfCells,1);
6175   mcIdType *retPtr=ret->getPointer();
6176   std::fill(retPtr,retPtr+nbOfCells,-1);
6177   mcIdType newCellId=0;
6178   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6179     {
6180       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6181         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6182           retPtr[std::distance(connI,i)]=newCellId++;
6183     }
6184   renumberCells(retPtr,false);
6185   return ret;
6186 }
6187
6188 /*!
6189  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6190  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6191  * This method makes asumption that connectivity is correctly set before calling.
6192  */
6193 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6194 {
6195   checkConnectivityFullyDefined();
6196   const mcIdType *conn=_nodal_connec->begin();
6197   const mcIdType *connI=_nodal_connec_index->begin();
6198   mcIdType nbOfCells=getNumberOfCells();
6199   std::vector<MEDCouplingUMesh *> ret;
6200   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6201     {
6202       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6203       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6204       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6205       mcIdType endCellId=ToIdType(std::distance(connI,i));
6206       mcIdType sz=endCellId-beginCellId;
6207       mcIdType *cells=new mcIdType[sz];
6208       for(mcIdType j=0;j<sz;j++)
6209         cells[j]=beginCellId+j;
6210       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6211       delete [] cells;
6212       ret.push_back(m);
6213     }
6214   return ret;
6215 }
6216
6217 /*!
6218  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6219  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6220  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6221  *
6222  * \return a newly allocated instance, that the caller must manage.
6223  * \throw If \a this contains more than one geometric type.
6224  * \throw If the nodal connectivity of \a this is not fully defined.
6225  * \throw If the internal data is not coherent.
6226  */
6227 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6228 {
6229   checkConnectivityFullyDefined();
6230   if(_types.size()!=1)
6231     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6232   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6233   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6234   ret->setCoords(getCoords());
6235   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6236   if(retC)
6237     {
6238       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6239       retC->setNodalConnectivity(c);
6240     }
6241   else
6242     {
6243       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6244       if(!retD)
6245         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6246       DataArrayIdType *c=0,*ci=0;
6247       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6248       MCAuto<DataArrayIdType> cs(c),cis(ci);
6249       retD->setNodalConnectivity(cs,cis);
6250     }
6251   return ret.retn();
6252 }
6253
6254 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6255 {
6256   checkConnectivityFullyDefined();
6257   if(_types.size()!=1)
6258     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6259   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6260   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6261   if(cm.isDynamic())
6262     {
6263       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6264       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6265       throw INTERP_KERNEL::Exception(oss.str());
6266     }
6267   mcIdType nbCells=getNumberOfCells();
6268   mcIdType typi=ToIdType(typ);
6269   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6270   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6271   mcIdType *outPtr=connOut->getPointer();
6272   const mcIdType *conn=_nodal_connec->begin();
6273   const mcIdType *connI=_nodal_connec_index->begin();
6274   nbNodesPerCell++;
6275   for(mcIdType i=0;i<nbCells;i++,connI++)
6276     {
6277       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6278         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6279       else
6280         {
6281           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 << ") !";
6282           throw INTERP_KERNEL::Exception(oss.str());
6283         }
6284     }
6285   return connOut.retn();
6286 }
6287
6288 /*!
6289  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6290  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6291  * \param nodalConn nodal connectivity
6292  * \param nodalConnIndex nodal connectivity indices
6293  */
6294 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6295 {
6296   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6297   checkConnectivityFullyDefined();
6298   if(_types.size()!=1)
6299     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6300   mcIdType nbCells=getNumberOfCells(),
6301            lgth=_nodal_connec->getNumberOfTuples();
6302   if(lgth<nbCells)
6303     throw INTERP_KERNEL::Exception(msg0);
6304   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6305   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6306   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6307   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6308   cip[0]=0;
6309   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6310     {
6311       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6312       mcIdType delta(stop-strt);
6313       if(delta>=1)
6314         {
6315           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6316             cp=std::copy(incp+strt,incp+stop,cp);
6317           else
6318             throw INTERP_KERNEL::Exception(msg0);
6319         }
6320       else
6321         throw INTERP_KERNEL::Exception(msg0);
6322       cip[1]=cip[0]+delta;
6323     }
6324   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6325 }
6326
6327 /*!
6328  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6329  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6330  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6331  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6332  * are not used here to avoid the build of big permutation array.
6333  *
6334  * \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
6335  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6336  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6337  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6338  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6339  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6340  * \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
6341  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6342  */
6343 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6344                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6345                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6346 {
6347   std::vector<const MEDCouplingUMesh *> ms2;
6348   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6349     if(*it)
6350       {
6351         (*it)->checkConnectivityFullyDefined();
6352         ms2.push_back(*it);
6353       }
6354   if(ms2.empty())
6355     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6356   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6357   int meshDim=ms2[0]->getMeshDimension();
6358   std::vector<const MEDCouplingUMesh *> m1ssm;
6359   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6360   //
6361   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6362   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6363   mcIdType fake=0,rk=0;
6364   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6365   ret1->alloc(0,1); ret2->alloc(0,1);
6366   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6367     {
6368       if(meshDim!=(*it)->getMeshDimension())
6369         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6370       if(refCoo!=(*it)->getCoords())
6371         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6372       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6373       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6374       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6375       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6376         {
6377           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6378           m1ssmSingleAuto.push_back(singleCell);
6379           m1ssmSingle.push_back(singleCell);
6380           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6381         }
6382     }
6383   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6384   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6385   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6386   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6387     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6388   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6389   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6390   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6391   return ret0.retn();
6392 }
6393
6394 /*!
6395  * This method returns a newly created DataArrayIdType instance.
6396  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6397  */
6398 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6399 {
6400   checkFullyDefined();
6401   const mcIdType *conn=_nodal_connec->begin();
6402   const mcIdType *connIndex=_nodal_connec_index->begin();
6403   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6404   for(const mcIdType *w=begin;w!=end;w++)
6405     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6406       ret->pushBackSilent(*w);
6407   return ret.retn();
6408 }
6409
6410 /*!
6411  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6412  * are in [0:getNumberOfCells())
6413  */
6414 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6415 {
6416   checkFullyDefined();
6417   const mcIdType *conn=_nodal_connec->begin();
6418   const mcIdType *connI=_nodal_connec_index->begin();
6419   mcIdType nbOfCells=getNumberOfCells();
6420   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6421   mcIdType *tmp=new mcIdType[nbOfCells];
6422   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6423     {
6424       mcIdType j=0;
6425       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6426         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6427           tmp[std::distance(connI,i)]=j++;
6428     }
6429   DataArrayIdType *ret=DataArrayIdType::New();
6430   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6431   ret->copyStringInfoFrom(*da);
6432   mcIdType *retPtr=ret->getPointer();
6433   const mcIdType *daPtr=da->begin();
6434   mcIdType nbOfElems=da->getNbOfElems();
6435   for(mcIdType k=0;k<nbOfElems;k++)
6436     retPtr[k]=tmp[daPtr[k]];
6437   delete [] tmp;
6438   return ret;
6439 }
6440
6441 /*!
6442  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6443  * This method \b works \b for mesh sorted by type.
6444  * cells whose ids is in 'idsPerGeoType' array.
6445  * This method conserves coords and name of mesh.
6446  */
6447 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6448 {
6449   std::vector<mcIdType> code=getDistributionOfTypes();
6450   std::size_t nOfTypesInThis=code.size()/3;
6451   mcIdType sz=0,szOfType=0;
6452   for(std::size_t i=0;i<nOfTypesInThis;i++)
6453     {
6454       if(code[3*i]!=type)
6455         sz+=code[3*i+1];
6456       else
6457         szOfType=code[3*i+1];
6458     }
6459   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6460     if(*work<0 || *work>=szOfType)
6461       {
6462         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6463         oss << ". It should be in [0," << szOfType << ") !";
6464         throw INTERP_KERNEL::Exception(oss.str());
6465       }
6466   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6467   mcIdType *idsPtr=idsTokeep->getPointer();
6468   mcIdType offset=0;
6469   for(std::size_t i=0;i<nOfTypesInThis;i++)
6470     {
6471       if(code[3*i]!=type)
6472         for(mcIdType j=0;j<code[3*i+1];j++)
6473           *idsPtr++=offset+j;
6474       else
6475         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6476       offset+=code[3*i+1];
6477     }
6478   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6479   ret->copyTinyInfoFrom(this);
6480   return ret.retn();
6481 }
6482
6483 /*!
6484  * This method returns a vector of size 'this->getNumberOfCells()'.
6485  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6486  */
6487 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6488 {
6489   mcIdType ncell=getNumberOfCells();
6490   std::vector<bool> ret(ncell);
6491   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6492   const mcIdType *c=getNodalConnectivity()->begin();
6493   for(mcIdType i=0;i<ncell;i++)
6494     {
6495       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6496       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6497       ret[i]=cm.isQuadratic();
6498     }
6499   return ret;
6500 }
6501
6502 /*!
6503  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6504  */
6505 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6506 {
6507   if(other->getType()!=UNSTRUCTURED)
6508     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6509   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6510   return MergeUMeshes(this,otherC);
6511 }
6512
6513 /*!
6514  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6515  * computed by averaging coordinates of cell nodes, so this method is not a right
6516  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6517  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6518  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6519  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6520  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6521  *          components. The caller is to delete this array using decrRef() as it is
6522  *          no more needed.
6523  *  \throw If the coordinates array is not set.
6524  *  \throw If the nodal connectivity of cells is not defined.
6525  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6526  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6527  */
6528 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6529 {
6530   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6531   int spaceDim=getSpaceDimension();
6532   mcIdType nbOfCells=getNumberOfCells();
6533   ret->alloc(nbOfCells,spaceDim);
6534   ret->copyStringInfoFrom(*getCoords());
6535   double *ptToFill=ret->getPointer();
6536   const mcIdType *nodal=_nodal_connec->begin();
6537   const mcIdType *nodalI=_nodal_connec_index->begin();
6538   const double *coor=_coords->begin();
6539   for(mcIdType i=0;i<nbOfCells;i++)
6540     {
6541       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6542       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6543       ptToFill+=spaceDim;
6544     }
6545   return ret.retn();
6546 }
6547
6548
6549 /*!
6550  * See computeCellCenterOfMass().
6551  *  \param eps a precision for the detection of degenerated arc of circles.
6552  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6553  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6554  *          components. The caller is to delete this array using decrRef() as it is
6555  *          no more needed.
6556  *  \throw If the coordinates array is not set.
6557  *  \throw If the nodal connectivity of cells is not defined.
6558  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6559  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6560  */
6561 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6562 {
6563   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6564   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6565   return ret.retn();
6566 }
6567
6568
6569 /*!
6570  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6571  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6572  *
6573  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6574  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6575  *
6576  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6577  * \throw If \a this is not fully defined (coordinates and connectivity)
6578  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6579  */
6580 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6581 {
6582   checkFullyDefined();
6583   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6584   int spaceDim=getSpaceDimension();
6585   mcIdType nbOfCells=getNumberOfCells();
6586   mcIdType nbOfNodes=getNumberOfNodes();
6587   ret->alloc(nbOfCells,spaceDim);
6588   double *ptToFill=ret->getPointer();
6589   const mcIdType *nodal=_nodal_connec->begin();
6590   const mcIdType *nodalI=_nodal_connec_index->begin();
6591   const double *coor=_coords->begin();
6592   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6593     {
6594       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6595       std::fill(ptToFill,ptToFill+spaceDim,0.);
6596       if(type!=INTERP_KERNEL::NORM_POLYHED)
6597         {
6598           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6599             {
6600               if(*conn>=0 && *conn<nbOfNodes)
6601                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6602               else
6603                 {
6604                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6605                   throw INTERP_KERNEL::Exception(oss.str());
6606                 }
6607             }
6608           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6609           if(nbOfNodesInCell>0)
6610             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6611           else
6612             {
6613               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6614               throw INTERP_KERNEL::Exception(oss.str());
6615             }
6616         }
6617       else
6618         {
6619           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6620           s.erase(-1);
6621           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6622             {
6623               if(*it>=0 && *it<nbOfNodes)
6624                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6625               else
6626                 {
6627                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6628                   throw INTERP_KERNEL::Exception(oss.str());
6629                 }
6630             }
6631           if(!s.empty())
6632             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6633           else
6634             {
6635               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6636               throw INTERP_KERNEL::Exception(oss.str());
6637             }
6638         }
6639     }
6640   return ret.retn();
6641 }
6642
6643 /*!
6644  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6645  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6646  * are specified via an array of cell ids.
6647  *  \warning Validity of the specified cell ids is not checked!
6648  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6649  *  \param [in] begin - an array of cell ids of interest.
6650  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6651  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6652  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6653  *          caller is to delete this array using decrRef() as it is no more needed.
6654  *  \throw If the coordinates array is not set.
6655  *  \throw If the nodal connectivity of cells is not defined.
6656  *
6657  *  \if ENABLE_EXAMPLES
6658  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6659  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6660  *  \endif
6661  */
6662 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6663 {
6664   DataArrayDouble *ret=DataArrayDouble::New();
6665   int spaceDim=getSpaceDimension();
6666   std::size_t nbOfTuple=std::distance(begin,end);
6667   ret->alloc(nbOfTuple,spaceDim);
6668   double *ptToFill=ret->getPointer();
6669   double *tmp=new double[spaceDim];
6670   const mcIdType *nodal=_nodal_connec->begin();
6671   const mcIdType *nodalI=_nodal_connec_index->begin();
6672   const double *coor=_coords->begin();
6673   for(const mcIdType *w=begin;w!=end;w++)
6674     {
6675       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6676       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6677       ptToFill+=spaceDim;
6678     }
6679   delete [] tmp;
6680   return ret;
6681 }
6682
6683 /*!
6684  * 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".
6685  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6686  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6687  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6688  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6689  *
6690  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6691  * \throw If spaceDim!=3 or meshDim!=2.
6692  * \throw If connectivity of \a this is invalid.
6693  * \throw If connectivity of a cell in \a this points to an invalid node.
6694  */
6695 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6696 {
6697   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6698   mcIdType nbOfCells=getNumberOfCells();
6699   mcIdType nbOfNodes(getNumberOfNodes());
6700   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6701     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6702   ret->alloc(nbOfCells,4);
6703   double *retPtr(ret->getPointer());
6704   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6705   const double *coor(_coords->begin());
6706   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6707     {
6708       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6709       if(nodalI[1]-nodalI[0]>=4)
6710         {
6711           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6712                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6713                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6714           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6715                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6716                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6717           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]};
6718           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]));
6719           for(int j=0;j<3;j++)
6720             {
6721               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6722               if(nodeId>=0 && nodeId<nbOfNodes)
6723                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6724               else
6725                 {
6726                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6727                   throw INTERP_KERNEL::Exception(oss.str());
6728                 }
6729             }
6730           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6731             {
6732               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6733               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6734             }
6735           else
6736             {
6737               if(nodalI[1]-nodalI[0]==4)
6738                 {
6739                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6740                   throw INTERP_KERNEL::Exception(oss.str());
6741                 }
6742               //
6743               double dd[3]={0.,0.,0.};
6744               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6745                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6746               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6747               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6748               std::copy(dd,dd+3,matrix+4*2);
6749               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6750               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6751             }
6752         }
6753       else
6754         {
6755           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6756           throw INTERP_KERNEL::Exception(oss.str());
6757         }
6758     }
6759   return ret.retn();
6760 }
6761
6762 /*!
6763  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6764  *
6765  */
6766 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6767 {
6768   if(!da)
6769     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6770   da->checkAllocated();
6771   std::string name(da->getName());
6772   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6773   if(name.empty())
6774     ret->setName("Mesh");
6775   ret->setCoords(da);
6776   mcIdType nbOfTuples(da->getNumberOfTuples());
6777   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6778   c->alloc(2*nbOfTuples,1);
6779   cI->alloc(nbOfTuples+1,1);
6780   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6781   *cip++=0;
6782   for(mcIdType i=0;i<nbOfTuples;i++)
6783     {
6784       *cp++=INTERP_KERNEL::NORM_POINT1;
6785       *cp++=i;
6786       *cip++=2*(i+1);
6787     }
6788   ret->setConnectivity(c,cI,true);
6789   return ret.retn();
6790 }
6791
6792 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6793 {
6794   if(!da)
6795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6796   da->checkAllocated();
6797   std::string name(da->getName());
6798   MCAuto<MEDCouplingUMesh> ret;
6799   {
6800     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6801     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6802     arr->alloc(da->getNumberOfTuples());
6803     tmp->setCoordsAt(0,arr);
6804     ret=tmp->buildUnstructured();
6805   }
6806   ret->setCoords(da);
6807   if(name.empty())
6808     ret->setName("Mesh");
6809   else
6810     ret->setName(name);
6811   return ret;
6812 }
6813
6814 /*!
6815  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6816  * Cells and nodes of
6817  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6818  *  \param [in] mesh1 - the first mesh.
6819  *  \param [in] mesh2 - the second mesh.
6820  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6821  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6822  *          is no more needed.
6823  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6824  *  \throw If the coordinates array is not set in none of the meshes.
6825  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6826  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6827  */
6828 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6829 {
6830   std::vector<const MEDCouplingUMesh *> tmp(2);
6831   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6832   return MergeUMeshes(tmp);
6833 }
6834
6835 /*!
6836  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6837  * Cells and nodes of
6838  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6839  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6840  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6841  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6842  *          is no more needed.
6843  *  \throw If \a a.size() == 0.
6844  *  \throw If \a a[ *i* ] == NULL.
6845  *  \throw If the coordinates array is not set in none of the meshes.
6846  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6847  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6848  */
6849 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6850 {
6851   std::size_t sz=a.size();
6852   if(sz==0)
6853     return MergeUMeshesLL(a);
6854   for(std::size_t ii=0;ii<sz;ii++)
6855     if(!a[ii])
6856       {
6857         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6858         throw INTERP_KERNEL::Exception(oss.str());
6859       }
6860   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6861   std::vector< const MEDCouplingUMesh * > aa(sz);
6862   int spaceDim=-3;
6863   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6864     {
6865       const MEDCouplingUMesh *cur=a[i];
6866       const DataArrayDouble *coo=cur->getCoords();
6867       if(coo)
6868         spaceDim=int(coo->getNumberOfComponents());
6869     }
6870   if(spaceDim==-3)
6871     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6872   for(std::size_t i=0;i<sz;i++)
6873     {
6874       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6875       aa[i]=bb[i];
6876     }
6877   return MergeUMeshesLL(aa);
6878 }
6879
6880 /*!
6881  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6882  * dimension and sharing the node coordinates array.
6883  * All cells of the first mesh precede all cells of the second mesh
6884  * within the result mesh.
6885  *  \param [in] mesh1 - the first mesh.
6886  *  \param [in] mesh2 - the second mesh.
6887  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6888  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6889  *          is no more needed.
6890  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6891  *  \throw If the meshes do not share the node coordinates array.
6892  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6893  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6894  */
6895 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6896 {
6897   std::vector<const MEDCouplingUMesh *> tmp(2);
6898   tmp[0]=mesh1; tmp[1]=mesh2;
6899   return MergeUMeshesOnSameCoords(tmp);
6900 }
6901
6902 /*!
6903  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6904  * dimension and sharing the node coordinates array.
6905  * All cells of the *i*-th mesh precede all cells of the
6906  * (*i*+1)-th mesh within the result mesh.
6907  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6908  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6909  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6910  *          is no more needed.
6911  *  \throw If \a a.size() == 0.
6912  *  \throw If \a a[ *i* ] == NULL.
6913  *  \throw If the meshes do not share the node coordinates array.
6914  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6915  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6916  */
6917 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6918 {
6919   if(meshes.empty())
6920     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6921   for(std::size_t ii=0;ii<meshes.size();ii++)
6922     if(!meshes[ii])
6923       {
6924         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6925         throw INTERP_KERNEL::Exception(oss.str());
6926       }
6927   const DataArrayDouble *coords=meshes.front()->getCoords();
6928   int meshDim=meshes.front()->getMeshDimension();
6929   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6930   mcIdType meshLgth=0;
6931   mcIdType meshIndexLgth=0;
6932   for(;iter!=meshes.end();iter++)
6933     {
6934       if(coords!=(*iter)->getCoords())
6935         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6936       if(meshDim!=(*iter)->getMeshDimension())
6937         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6938       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6939       meshIndexLgth+=(*iter)->getNumberOfCells();
6940     }
6941   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6942   nodal->alloc(meshLgth,1);
6943   mcIdType *nodalPtr=nodal->getPointer();
6944   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6945   nodalIndex->alloc(meshIndexLgth+1,1);
6946   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6947   mcIdType offset=0;
6948   for(iter=meshes.begin();iter!=meshes.end();iter++)
6949     {
6950       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6951       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6952       mcIdType nbOfCells=(*iter)->getNumberOfCells();
6953       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6954       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6955       if(iter!=meshes.begin())
6956         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6957       else
6958         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6959       offset+=meshLgth2;
6960     }
6961   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6962   ret->setName("merge");
6963   ret->setMeshDimension(meshDim);
6964   ret->setConnectivity(nodal,nodalIndex,true);
6965   ret->setCoords(coords);
6966   return ret;
6967 }
6968
6969 /*!
6970  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6971  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6972  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6973  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6974  * New" mode are returned for each input mesh.
6975  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6976  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
6977  *          valid values [0,1,2], see zipConnectivityTraducer().
6978  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6979  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6980  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
6981  *          no more needed.
6982  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6983  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6984  *          is no more needed.
6985  *  \throw If \a meshes.size() == 0.
6986  *  \throw If \a meshes[ *i* ] == NULL.
6987  *  \throw If the meshes do not share the node coordinates array.
6988  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6989  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
6990  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6991  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
6992  */
6993 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6994 {
6995   //All checks are delegated to MergeUMeshesOnSameCoords
6996   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6997   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6998   corr.resize(meshes.size());
6999   std::size_t nbOfMeshes=meshes.size();
7000   mcIdType offset=0;
7001   const mcIdType *o2nPtr=o2n->begin();
7002   for(std::size_t i=0;i<nbOfMeshes;i++)
7003     {
7004       DataArrayIdType *tmp=DataArrayIdType::New();
7005       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7006       tmp->alloc(curNbOfCells,1);
7007       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7008       offset+=curNbOfCells;
7009       tmp->setName(meshes[i]->getName());
7010       corr[i]=tmp;
7011     }
7012   return ret.retn();
7013 }
7014
7015 /*!
7016  * Makes all given meshes share the nodal connectivity array. The common connectivity
7017  * array is created by concatenating the connectivity arrays of all given meshes. All
7018  * the given meshes must be of the same space dimension but dimension of cells **can
7019  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7020  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7021  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7022  *  \param [in,out] meshes - a vector of meshes to update.
7023  *  \throw If any of \a meshes is NULL.
7024  *  \throw If the coordinates array is not set in any of \a meshes.
7025  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7026  *  \throw If \a meshes are of different space dimension.
7027  */
7028 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7029 {
7030   std::size_t sz=meshes.size();
7031   if(sz==0 || sz==1)
7032     return;
7033   std::vector< const DataArrayDouble * > coords(meshes.size());
7034   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7035   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7036     {
7037       if((*it))
7038         {
7039           (*it)->checkConnectivityFullyDefined();
7040           const DataArrayDouble *coo=(*it)->getCoords();
7041           if(coo)
7042             *it2=coo;
7043           else
7044             {
7045               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7046               oss << " has no coordinate array defined !";
7047               throw INTERP_KERNEL::Exception(oss.str());
7048             }
7049         }
7050       else
7051         {
7052           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7053           oss << " is null !";
7054           throw INTERP_KERNEL::Exception(oss.str());
7055         }
7056     }
7057   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7058   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7059   mcIdType offset=(*it)->getNumberOfNodes();
7060   (*it++)->setCoords(res);
7061   for(;it!=meshes.end();it++)
7062     {
7063       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7064       (*it)->setCoords(res);
7065       (*it)->shiftNodeNumbersInConn(offset);
7066       offset+=oldNumberOfNodes;
7067     }
7068 }
7069
7070 /*!
7071  * Merges nodes coincident with a given precision within all given meshes that share
7072  * the nodal connectivity array. The given meshes **can be of different** mesh
7073  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7074  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7075  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7076  *  \param [in,out] meshes - a vector of meshes to update.
7077  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7078  *  \throw If any of \a meshes is NULL.
7079  *  \throw If the \a meshes do not share the same node coordinates array.
7080  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7081  */
7082 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7083 {
7084   if(meshes.empty())
7085     return ;
7086   std::set<const DataArrayDouble *> s;
7087   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7088     {
7089       if(*it)
7090         s.insert((*it)->getCoords());
7091       else
7092         {
7093           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 !";
7094           throw INTERP_KERNEL::Exception(oss.str());
7095         }
7096     }
7097   if(s.size()!=1)
7098     {
7099       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 !";
7100       throw INTERP_KERNEL::Exception(oss.str());
7101     }
7102   const DataArrayDouble *coo=*(s.begin());
7103   if(!coo)
7104     return;
7105   //
7106   DataArrayIdType *comm,*commI;
7107   coo->findCommonTuples(eps,-1,comm,commI);
7108   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7109   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7110   mcIdType newNbOfNodes;
7111   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7112   if(oldNbOfNodes==newNbOfNodes)
7113     return ;
7114   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7115   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7116     {
7117       (*it)->renumberNodesInConn(o2n->begin());
7118       (*it)->setCoords(newCoords);
7119     }
7120 }
7121
7122
7123 /*!
7124  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7125  */
7126 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7127 {
7128   std::size_t i, ip1;
7129   double v[3]={0.,0.,0.};
7130   std::size_t sz=std::distance(begin,end);
7131   if(!isQuadratic)
7132     for(i=0;i<sz;i++)
7133       {
7134         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7135         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7136         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];
7137         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7138         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7139       }
7140   else
7141     {
7142       // Same algorithm as above but also using intermediate quadratic points.
7143       // (taking only linear points might lead to issues if the linearized version of the
7144       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7145       std::size_t hsz = sz/2;
7146       for(std::size_t j=0;j<sz;j++)
7147         {
7148           if (j%2)  // current point i is quadratic, next point i+1 is standard
7149             {
7150               i = hsz+(j-1)/2;
7151               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7152             }
7153           else      // current point i is standard, next point i+1 is quadratic
7154             {
7155               i = j/2;
7156               ip1 = j/2+hsz;
7157             }
7158           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7159           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7160           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7161         }
7162     }
7163   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7164   return (ret>0.);
7165 }
7166
7167 /*!
7168  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7169  */
7170 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7171 {
7172   std::vector<std::pair<mcIdType,mcIdType> > edges;
7173   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7174   const mcIdType *bgFace=begin;
7175   for(std::size_t i=0;i<nbOfFaces;i++)
7176     {
7177       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7178       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7179       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7180         {
7181           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7182           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7183             return false;
7184           edges.push_back(p1);
7185         }
7186       bgFace=endFace+1;
7187     }
7188   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7189 }
7190
7191 /*!
7192  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7193  */
7194 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7195 {
7196   double vec0[3],vec1[3];
7197   std::size_t sz=std::distance(begin,end);
7198   if(sz%2!=0)
7199     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7200   mcIdType nbOfNodes=ToIdType(sz/2);
7201   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7202   const double *pt0=coords+3*begin[0];
7203   const double *pt1=coords+3*begin[nbOfNodes];
7204   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7205   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7206 }
7207
7208 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7209 {
7210   std::size_t sz=std::distance(begin,end);
7211   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7212   std::size_t nbOfNodes(sz/2);
7213   std::copy(begin,end,(mcIdType *)tmp);
7214   for(std::size_t j=1;j<nbOfNodes;j++)
7215     {
7216       begin[j]=tmp[nbOfNodes-j];
7217       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7218     }
7219 }
7220
7221 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7222 {
7223   std::size_t sz=std::distance(begin,end);
7224   if(sz!=4)
7225     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7226   double vec0[3],vec1[3];
7227   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7228   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];
7229   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;
7230 }
7231
7232 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7233 {
7234   std::size_t sz=std::distance(begin,end);
7235   if(sz!=5)
7236     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7237   double vec0[3];
7238   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7239   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7240   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7241 }
7242
7243 /*!
7244  * 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 )
7245  * 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
7246  * a 2D space.
7247  *
7248  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7249  * \param [in] coords the coordinates with nb of components exactly equal to 3
7250  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7251  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7252  */
7253 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7254                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7255 {
7256   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7257   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7258   double *vPtr=v->getPointer();
7259   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7260   double *pPtr=p->getPointer();
7261   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7262   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7263   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7264     {
7265       mcIdType face = e_f[e_fi[index] + i];
7266       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7267       // to differentiate faces going to different cells:
7268       pPtr++, *pPtr = 0;
7269       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7270         *pPtr += FromIdType<double>(f_e[j]);
7271     }
7272   pPtr=p->getPointer(); vPtr=v->getPointer();
7273   DataArrayIdType *comm1=0,*commI1=0;
7274   v->findCommonTuples(eps,-1,comm1,commI1);
7275   for (mcIdType i = 0; i < nbFaces; i++)
7276     if (comm1->findIdFirstEqual(i) < 0)
7277       {
7278         comm1->pushBackSilent(i);
7279         commI1->pushBackSilent(comm1->getNumberOfTuples());
7280       }
7281   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7282   const mcIdType *comm1Ptr=comm1->begin();
7283   const mcIdType *commI1Ptr=commI1->begin();
7284   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7285   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7286   //
7287   for(mcIdType i=0;i<nbOfGrps1;i++)
7288     {
7289       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7290       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7291       DataArrayIdType *comm2=0,*commI2=0;
7292       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7293       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7294         if (comm2->findIdFirstEqual(j) < 0)
7295           {
7296             comm2->pushBackSilent(j);
7297             commI2->pushBackSilent(comm2->getNumberOfTuples());
7298           }
7299       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7300       const mcIdType *comm2Ptr=comm2->begin();
7301       const mcIdType *commI2Ptr=commI2->begin();
7302       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7303       for(mcIdType j=0;j<nbOfGrps2;j++)
7304         {
7305           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7306             {
7307               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7308               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7309               res->pushBackSilent(-1);
7310             }
7311           else
7312             {
7313               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7314               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7315               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7316               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7317               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7318               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7319               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7320               const mcIdType *idsNodePtr=idsNode->begin();
7321               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];
7322               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7323               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7324               if(std::abs(norm)>eps)
7325                 {
7326                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7327                   mm3->rotate(center,vec,angle);
7328                 }
7329               mm3->changeSpaceDimension(2);
7330               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7331               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7332               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7333               mcIdType nbOfCells=mm4->getNumberOfCells();
7334               for(mcIdType k=0;k<nbOfCells;k++)
7335                 {
7336                   int l=0;
7337                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7338                     res->pushBackSilent(idsNodePtr[*work]);
7339                   res->pushBackSilent(-1);
7340                 }
7341             }
7342         }
7343     }
7344   res->popBackSilent();
7345 }
7346
7347 /*!
7348  * 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
7349  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7350  *
7351  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7352  * \param [in] coords coordinates expected to have 3 components.
7353  * \param [in] begin start of the nodal connectivity of the face.
7354  * \param [in] end end of the nodal connectivity (excluded) of the face.
7355  * \param [out] v the normalized vector of size 3
7356  * \param [out] p the pos of plane
7357  */
7358 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7359 {
7360   std::size_t nbPoints=std::distance(begin,end);
7361   if(nbPoints<3)
7362     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7363   double vec[3]={0.,0.,0.};
7364   std::size_t j=0;
7365   bool refFound=false;
7366   for(;j<nbPoints-1 && !refFound;j++)
7367     {
7368       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7369       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7370       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7371       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7372       if(norm>eps)
7373         {
7374           refFound=true;
7375           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7376         }
7377     }
7378   for(std::size_t i=j;i<nbPoints-1;i++)
7379     {
7380       double curVec[3];
7381       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7382       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7383       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7384       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7385       if(norm<eps)
7386         continue;
7387       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7388       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];
7389       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7390       if(norm>eps)
7391         {
7392           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7393           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7394           return ;
7395         }
7396     }
7397   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7398 }
7399
7400 /*!
7401  * This method tries to obtain a well oriented polyhedron.
7402  * If the algorithm fails, an exception will be thrown.
7403  */
7404 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7405 {
7406   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7407   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7408   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7409   isPerm[0]=true;
7410   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7411   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7412   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7413   //
7414   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7415     {
7416       bgFace=begin;
7417       std::size_t smthChanged=0;
7418       for(std::size_t i=0;i<nbOfFaces;i++)
7419         {
7420           endFace=std::find(bgFace+1,end,-1);
7421           nbOfEdgesInFace=std::distance(bgFace,endFace);
7422           if(!isPerm[i])
7423             {
7424               bool b=false;
7425               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7426                 {
7427                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7428                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7429                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7430                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7431                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7432                 }
7433               if(isPerm[i])
7434                 {
7435                   if(!b)
7436                     std::reverse(bgFace+1,endFace);
7437                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7438                     {
7439                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7440                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7441                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7442                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7443                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7444                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7445                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7446                       if(it!=edgesOK.end())
7447                         {
7448                           edgesOK.erase(it);
7449                           edgesFinished.push_back(p1);
7450                         }
7451                       else
7452                         edgesOK.push_back(p1);
7453                     }
7454                 }
7455             }
7456           bgFace=endFace+1;
7457         }
7458       if(smthChanged==0)
7459         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7460     }
7461   if(!edgesOK.empty())
7462     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7463   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7464     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7465       bgFace=begin;
7466       for(std::size_t i=0;i<nbOfFaces;i++)
7467         {
7468           endFace=std::find(bgFace+1,end,-1);
7469           std::reverse(bgFace+1,endFace);
7470           bgFace=endFace+1;
7471         }
7472     }
7473 }
7474
7475
7476 /*!
7477  * This method makes the assumption spacedimension == meshdimension == 2.
7478  * This method works only for linear cells.
7479  *
7480  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7481  */
7482 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7483 {
7484   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7485     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7486   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7487   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7488   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7489   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7490   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7491   mcIdType nbCells=skin->getNumberOfCells();
7492   if(nbCells==nbOfNodesExpected)
7493     return buildUnionOf2DMeshLinear(skin,n2o);
7494   else if(2*nbCells==nbOfNodesExpected)
7495     return buildUnionOf2DMeshQuadratic(skin,n2o);
7496   else
7497     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7498 }
7499
7500 /*!
7501  * This method makes the assumption spacedimension == meshdimension == 3.
7502  * This method works only for linear cells.
7503  *
7504  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7505  */
7506 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7507 {
7508   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7509     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7510   MCAuto<MEDCouplingUMesh> m=computeSkin();
7511   const mcIdType *conn=m->getNodalConnectivity()->begin();
7512   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7513   mcIdType nbOfCells=m->getNumberOfCells();
7514   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7515   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7516   if(nbOfCells<1)
7517     return ret.retn();
7518   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7519   for(mcIdType i=1;i<nbOfCells;i++)
7520     {
7521       *work++=-1;
7522       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7523     }
7524   return ret.retn();
7525 }
7526
7527 /*!
7528  * \brief Creates a graph of cell neighbors
7529  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7530  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7531  *  For example
7532  *  - index:  0 3 5 6 6
7533  *  - value:  1 2 3 2 3 3
7534  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7535  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7536  */
7537 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7538 {
7539   checkConnectivityFullyDefined();
7540
7541   int meshDim = this->getMeshDimension();
7542   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7543   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7544   this->getReverseNodalConnectivity(revConn,indexr);
7545   const mcIdType* indexr_ptr=indexr->begin();
7546   const mcIdType* revConn_ptr=revConn->begin();
7547
7548   const MEDCoupling::DataArrayIdType* index;
7549   const MEDCoupling::DataArrayIdType* conn;
7550   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7551   index=this->getNodalConnectivityIndex();
7552   mcIdType nbCells=this->getNumberOfCells();
7553   const mcIdType* index_ptr=index->begin();
7554   const mcIdType* conn_ptr=conn->begin();
7555
7556   //creating graph arcs (cell to cell relations)
7557   //arcs are stored in terms of (index,value) notation
7558   // 0 3 5 6 6
7559   // 1 2 3 2 3 3
7560   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7561   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7562
7563   //warning here one node have less than or equal effective number of cell with it
7564   //but cell could have more than effective nodes
7565   //because other equals nodes in other domain (with other global inode)
7566   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7567   std::vector <mcIdType> cell2cell;
7568   cell2cell.reserve(3*nbCells);
7569
7570   for (mcIdType icell=0; icell<nbCells;icell++)
7571     {
7572       std::map<mcIdType,mcIdType > counter;
7573       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7574         {
7575           mcIdType inode=conn_ptr[iconn];
7576           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7577             {
7578               mcIdType icell2=revConn_ptr[iconnr];
7579               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7580               if (iter!=counter.end()) (iter->second)++;
7581               else counter.insert(std::make_pair(icell2,1));
7582             }
7583         }
7584       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7585            iter!=counter.end(); iter++)
7586         if (iter->second >= meshDim)
7587           {
7588             cell2cell_index[icell+1]++;
7589             cell2cell.push_back(iter->first);
7590           }
7591     }
7592   indexr->decrRef();
7593   revConn->decrRef();
7594   cell2cell_index[0]=0;
7595   for (mcIdType icell=0; icell<nbCells;icell++)
7596     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7597
7598   //filling up index and value to create skylinearray structure
7599   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7600   return array;
7601 }
7602
7603
7604 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7605 {
7606   mcIdType nbOfCells=getNumberOfCells();
7607   if(nbOfCells<=0)
7608     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7609   ofs << "  <" << getVTKDataSetType() << ">\n";
7610   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7611   ofs << "      <PointData>\n" << pointData << std::endl;
7612   ofs << "      </PointData>\n";
7613   ofs << "      <CellData>\n" << cellData << std::endl;
7614   ofs << "      </CellData>\n";
7615   ofs << "      <Points>\n";
7616   if(getSpaceDimension()==3)
7617     _coords->writeVTK(ofs,8,"Points",byteData);
7618   else
7619     {
7620       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7621       coo->writeVTK(ofs,8,"Points",byteData);
7622     }
7623   ofs << "      </Points>\n";
7624   ofs << "      <Cells>\n";
7625   const mcIdType *cPtr=_nodal_connec->begin();
7626   const mcIdType *cIPtr=_nodal_connec_index->begin();
7627   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7628   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7629   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7630   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7631   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7632   mcIdType szFaceOffsets=0,szConn=0;
7633   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7634     {
7635       *w2=cPtr[cIPtr[i]];
7636       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7637         {
7638           *w1=-1;
7639           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7640           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7641         }
7642       else
7643         {
7644           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7645           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7646           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7647           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7648           w4=std::copy(c.begin(),c.end(),w4);
7649         }
7650     }
7651   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7652   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7653     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7654   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7655   types->writeVTK(ofs,8,"UInt8","types",byteData);
7656   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7657   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7658   if(szFaceOffsets!=0)
7659     {//presence of Polyhedra
7660       connectivity->reAlloc(szConn);
7661       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7662       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7663       w1=faces->getPointer();
7664       for(mcIdType i=0;i<nbOfCells;i++)
7665         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7666           {
7667             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7668             *w1++=nbFaces;
7669             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7670             for(mcIdType j=0;j<nbFaces;j++)
7671               {
7672                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7673                 *w1++=ToIdType(std::distance(w6,w5));
7674                 w1=std::copy(w6,w5,w1);
7675                 w6=w5+1;
7676               }
7677           }
7678       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7679     }
7680   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7681   ofs << "      </Cells>\n";
7682   ofs << "    </Piece>\n";
7683   ofs << "  </" << getVTKDataSetType() << ">\n";
7684 }
7685
7686 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7687 {
7688   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7689   if(_mesh_dim==-2)
7690     { stream << " Not set !"; return ; }
7691   stream << " Mesh dimension : " << _mesh_dim << ".";
7692   if(_mesh_dim==-1)
7693     return ;
7694   if(!_coords)
7695     { stream << " No coordinates set !"; return ; }
7696   if(!_coords->isAllocated())
7697     { stream << " Coordinates set but not allocated !"; return ; }
7698   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7699   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7700   if(!_nodal_connec_index)
7701     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7702   if(!_nodal_connec_index->isAllocated())
7703     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7704   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7705   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7706   if(cpt!=1 || lgth<1)
7707     return ;
7708   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7709 }
7710
7711 std::string MEDCouplingUMesh::getVTKDataSetType() const
7712 {
7713   return std::string("UnstructuredGrid");
7714 }
7715
7716 std::string MEDCouplingUMesh::getVTKFileExtension() const
7717 {
7718   return std::string("vtu");
7719 }
7720
7721
7722
7723 /**
7724  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7725  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7726  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7727  * The caller is to deal with the resulting DataArrayIdType.
7728  *  \throw If the coordinate array is not set.
7729  *  \throw If the nodal connectivity of the cells is not defined.
7730  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7731  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7732  *
7733  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7734  */
7735 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7736 {
7737   checkFullyDefined();
7738   if(getMeshDimension()!=1)
7739     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7740
7741   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7742   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7743   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7744   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7745   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7746   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7747   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7748   const mcIdType * dsi(_dsi->begin());
7749   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7750   m_points=0;
7751   if (dsii->getNumberOfTuples())
7752     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7753
7754   mcIdType nc=getNumberOfCells();
7755   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7756   result->alloc(nc,1);
7757
7758   // set of edges not used so far
7759   std::set<mcIdType> edgeSet;
7760   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7761
7762   mcIdType startSeg=0;
7763   mcIdType newIdx=0;
7764   // while we have points with only one neighbor segments
7765   do
7766     {
7767       std::list<mcIdType> linePiece;
7768       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7769       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7770         {
7771           // Fill the list forward (resp. backward) from the start segment:
7772           mcIdType activeSeg = startSeg;
7773           mcIdType prevPointId = -20;
7774           mcIdType ptId;
7775           while (!edgeSet.empty())
7776             {
7777               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7778                 {
7779                   if (direction==0)
7780                     linePiece.push_back(activeSeg);
7781                   else
7782                     linePiece.push_front(activeSeg);
7783                   edgeSet.erase(activeSeg);
7784                 }
7785
7786               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7787               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7788               if (dsi[ptId] == 1) // hitting the end of the line
7789                 break;
7790               prevPointId = ptId;
7791               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7792               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7793             }
7794         }
7795       // Done, save final piece into DA:
7796       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7797       newIdx += ToIdType(linePiece.size());
7798
7799       // identify next valid start segment (one which is not consumed)
7800       if(!edgeSet.empty())
7801         startSeg = *(edgeSet.begin());
7802     }
7803   while (!edgeSet.empty());
7804   return result.retn();
7805 }
7806
7807 /**
7808  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7809  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7810  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7811  * a minimal creation of new nodes is wanted.
7812  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7813  * nodes if a SEG3 is split without information of middle.
7814  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7815  * avoid to have a non conform mesh.
7816  *
7817  * \return mcIdType - the number of new nodes created (in most of cases 0).
7818  *
7819  * \throw If \a this is not coherent.
7820  * \throw If \a this has not spaceDim equal to 2.
7821  * \throw If \a this has not meshDim equal to 2.
7822  * \throw If some subcells needed to be split are orphan.
7823  * \sa MEDCouplingUMesh::conformize2D
7824  */
7825 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7826 {
7827   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7828     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7829   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7830   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7831     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7832   if(midOpt==0 && midOptI==0)
7833     {
7834       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7835       return 0;
7836     }
7837   else if(midOpt!=0 && midOptI!=0)
7838     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7839   else
7840     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7841 }
7842
7843 /*!
7844  * 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
7845  * 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
7846  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7847  * 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
7848  * 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.
7849  *
7850  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7851  */
7852 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7853 {
7854   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7855   if(sz>=4)
7856     {
7857       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7858       if(cm.getDimension()==2)
7859         {
7860           const mcIdType *node=nodalConnBg+1;
7861           mcIdType startNode=*node++;
7862           double refX=coords[2*startNode];
7863           for(;node!=nodalConnEnd;node++)
7864             {
7865               if(coords[2*(*node)]<refX)
7866                 {
7867                   startNode=*node;
7868                   refX=coords[2*startNode];
7869                 }
7870             }
7871           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7872           refX=1e300;
7873           double tmp1;
7874           double tmp2[2];
7875           double angle0=-M_PI/2;
7876           //
7877           mcIdType nextNode=-1;
7878           mcIdType prevNode=-1;
7879           double resRef;
7880           double angleNext=0.;
7881           while(nextNode!=startNode)
7882             {
7883               nextNode=-1;
7884               resRef=1e300;
7885               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7886                 {
7887                   if(*node!=tmpOut.back() && *node!=prevNode)
7888                     {
7889                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7890                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7891                       double res;
7892                       if(angleM<=angle0)
7893                         res=angle0-angleM;
7894                       else
7895                         res=angle0-angleM+2.*M_PI;
7896                       if(res<resRef)
7897                         {
7898                           nextNode=*node;
7899                           resRef=res;
7900                           angleNext=angleM;
7901                         }
7902                     }
7903                 }
7904               if(nextNode!=startNode)
7905                 {
7906                   angle0=angleNext-M_PI;
7907                   if(angle0<-M_PI)
7908                     angle0+=2*M_PI;
7909                   prevNode=tmpOut.back();
7910                   tmpOut.push_back(nextNode);
7911                 }
7912             }
7913           std::vector<mcIdType> tmp3(2*(sz-1));
7914           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7915           std::copy(nodalConnBg+1,nodalConnEnd,it);
7916           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7917             {
7918               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7919               return false;
7920             }
7921           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7922             {
7923               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7924               return false;
7925             }
7926           else
7927             {
7928               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7929               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7930               return true;
7931             }
7932         }
7933       else
7934         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7935     }
7936   else
7937     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7938 }
7939
7940 /*!
7941  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7942  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7943  * 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]].
7944  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7945  * A negative value in \b arrIn means that it is ignored.
7946  * 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.
7947  *
7948  * \param [in] arrIn arr origin array from which the extraction will be done.
7949  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7950  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7951  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7952  */
7953 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7954 {
7955   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7956   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7957 }
7958
7959 /*!
7960  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7961  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7962  * 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]].
7963  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7964  * A negative value in \b arrIn means that it is ignored.
7965  * 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.
7966  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7967  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7968  * \param [in] arrIn arr origin array from which the extraction will be done.
7969  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7970  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7971  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7972  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7973  * \sa MEDCouplingUMesh::partitionBySpreadZone
7974  */
7975 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7976 {
7977   nbOfDepthPeelingPerformed=0;
7978   if(!arrIndxIn)
7979     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7980   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7981   if(nbOfTuples<=0)
7982     {
7983       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7984       return ret;
7985     }
7986   //
7987   std::vector<bool> fetched(nbOfTuples,false);
7988   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7989 }
7990
7991
7992
7993 /*!
7994  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7995  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7996  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7997  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7998  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7999  *
8000  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8001  */
8002 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8003 {
8004   checkFullyDefined();
8005   int mdim=getMeshDimension();
8006   int spaceDim=getSpaceDimension();
8007   if(mdim!=spaceDim)
8008     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8009   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8010   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8011   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8012   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8013   ret->setCoords(getCoords());
8014   ret->allocateCells(ToIdType(partition.size()));
8015   //
8016   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8017     {
8018       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8019       MCAuto<DataArrayIdType> cell;
8020       switch(mdim)
8021       {
8022         case 2:
8023           cell=tmp->buildUnionOf2DMesh();
8024           break;
8025         case 3:
8026           cell=tmp->buildUnionOf3DMesh();
8027           break;
8028         default:
8029           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8030       }
8031
8032       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8033     }
8034   //
8035   ret->finishInsertingCells();
8036   return ret.retn();
8037 }
8038
8039 /*!
8040  * This method partitions \b this into contiguous zone.
8041  * This method only needs a well defined connectivity. Coordinates are not considered here.
8042  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8043  */
8044 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8045 {
8046   DataArrayIdType *neigh=0,*neighI=0;
8047   computeNeighborsOfCells(neigh,neighI);
8048   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8049   return PartitionBySpreadZone(neighAuto,neighIAuto);
8050 }
8051
8052 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8053 {
8054   if(!arrIn || !arrIndxIn)
8055     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8056   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8057   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8058   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8059     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8060   mcIdType nbOfCellsCur(nbOfTuples-1);
8061   std::vector<DataArrayIdType *> ret;
8062   if(nbOfCellsCur<=0)
8063     return ret;
8064   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8065   std::vector< MCAuto<DataArrayIdType> > ret2;
8066   mcIdType seed=0;
8067   while(seed<nbOfCellsCur)
8068     {
8069       mcIdType nbOfPeelPerformed=0;
8070       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8071       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8072     }
8073   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8074     ret.push_back((*it).retn());
8075   return ret;
8076 }
8077
8078 /*!
8079  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8080  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8081  *
8082  * \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.
8083  * \return a newly allocated DataArrayIdType to be managed by the caller.
8084  * \throw In case of \a code has not the right format (typically of size 3*n)
8085  */
8086 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8087 {
8088   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8089   std::size_t nb=code.size()/3;
8090   if(code.size()%3!=0)
8091     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8092   ret->alloc(nb,2);
8093   mcIdType *retPtr=ret->getPointer();
8094   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8095     {
8096       retPtr[0]=code[3*i+2];
8097       retPtr[1]=code[3*i+2]+code[3*i+1];
8098     }
8099   return ret.retn();
8100 }
8101
8102 /*!
8103  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8104  * All cells in \a this are expected to be linear 3D cells.
8105  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8106  * It leads to an increase to number of cells.
8107  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8108  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8109  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8110  *
8111  * \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.
8112  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8113  * \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.
8114  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8115  *          an id of old cell producing it. The caller is to delete this array using
8116  *         decrRef() as it is no more needed.
8117  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8118  *
8119  * \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
8120  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8121  *
8122  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8123  * \throw If \a this is not fully constituted with linear 3D cells.
8124  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8125  */
8126 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8127 {
8128   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8129   checkConnectivityFullyDefined();
8130   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8131     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8132   mcIdType nbOfCells=getNumberOfCells();
8133   mcIdType nbNodes(getNumberOfNodes());
8134   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8135   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8136   mcIdType *retPt(ret->getPointer());
8137   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8138   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8139   const mcIdType *oldc(_nodal_connec->begin());
8140   const mcIdType *oldci(_nodal_connec_index->begin());
8141   const double *coords(_coords->begin());
8142   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8143     {
8144       std::vector<mcIdType> a; std::vector<double> b;
8145       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8146       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8147       const mcIdType *aa(&a[0]);
8148       if(!b.empty())
8149         {
8150           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8151             if(*it<0)
8152               *it=(-(*(it))-1+nbNodes);
8153           addPts->insertAtTheEnd(b.begin(),b.end());
8154           nbNodes+=ToIdType(b.size()/3);
8155         }
8156       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8157         newConn->insertAtTheEnd(aa,aa+4);
8158     }
8159   if(!addPts->empty())
8160     {
8161       addPts->rearrange(3);
8162       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8163       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8164       ret0->setCoords(addPts);
8165     }
8166   else
8167     {
8168       nbOfAdditionalPoints=0;
8169       ret0->setCoords(getCoords());
8170     }
8171   ret0->setNodalConnectivity(newConn);
8172   //
8173   ret->computeOffsetsFull();
8174   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8175   return ret0.retn();
8176 }
8177
8178 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8179     _own_cell(true),_cell_id(-1),_nb_cell(0)
8180 {
8181   if(mesh)
8182     {
8183       mesh->incrRef();
8184       _nb_cell=mesh->getNumberOfCells();
8185     }
8186 }
8187
8188 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8189 {
8190   if(_mesh)
8191     _mesh->decrRef();
8192   if(_own_cell)
8193     delete _cell;
8194 }
8195
8196 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8197     _own_cell(false),_cell_id(bg-1),
8198     _nb_cell(end)
8199 {
8200   if(mesh)
8201     mesh->incrRef();
8202 }
8203
8204 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8205 {
8206   _cell_id++;
8207   if(_cell_id<_nb_cell)
8208     {
8209       _cell->next();
8210       return _cell;
8211     }
8212   else
8213     return 0;
8214 }
8215
8216 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8217 {
8218   if(_mesh)
8219     _mesh->incrRef();
8220 }
8221
8222 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8223 {
8224   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8225 }
8226
8227 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8228 {
8229   if(_mesh)
8230     _mesh->decrRef();
8231 }
8232
8233 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8234     _itc(itc),
8235     _bg(bg),_end(end)
8236 {
8237   if(_mesh)
8238     _mesh->incrRef();
8239 }
8240
8241 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8242 {
8243   if(_mesh)
8244     _mesh->decrRef();
8245 }
8246
8247 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8248 {
8249   return _type;
8250 }
8251
8252 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8253 {
8254   return _end-_bg;
8255 }
8256
8257 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8258 {
8259   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8260 }
8261
8262 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8263 {
8264   if(mesh)
8265     {
8266       mesh->incrRef();
8267       _nb_cell=mesh->getNumberOfCells();
8268     }
8269 }
8270
8271 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8272 {
8273   if(_mesh)
8274     _mesh->decrRef();
8275   delete _cell;
8276 }
8277
8278 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8279 {
8280   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8281   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8282   if(_cell_id<_nb_cell)
8283     {
8284       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8285       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8286       mcIdType startId=_cell_id;
8287       _cell_id+=nbOfElems;
8288       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8289     }
8290   else
8291     return 0;
8292 }
8293
8294 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8295 {
8296   if(mesh)
8297     {
8298       _conn=mesh->getNodalConnectivity()->getPointer();
8299       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8300     }
8301 }
8302
8303 void MEDCouplingUMeshCell::next()
8304 {
8305   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8306     {
8307       _conn+=_conn_lgth;
8308       _conn_indx++;
8309     }
8310   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8311 }
8312
8313 std::string MEDCouplingUMeshCell::repr() const
8314 {
8315   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8316     {
8317       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8318       oss << " : ";
8319       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8320       return oss.str();
8321     }
8322   else
8323     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8324 }
8325
8326 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8327 {
8328   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8329     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8330   else
8331     return INTERP_KERNEL::NORM_ERROR;
8332 }
8333
8334 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8335 {
8336   lgth=_conn_lgth;
8337   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8338     return _conn;
8339   else
8340     return 0;
8341 }