Salome HOME
0762ba2667dffe862b1de8b533bce5d078e78839
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1344  *             precision.
1345  */
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1347 {
1348   checkFullyDefined();
1349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352   coords->recenterForMaxPrecision(eps);
1353   //
1354   mcIdType nbOfCells=getNumberOfCells();
1355   const mcIdType *conn=_nodal_connec->getConstPointer();
1356   const mcIdType *index=_nodal_connec_index->getConstPointer();
1357   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358   connINew->alloc(nbOfCells+1,1);
1359   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1363   bool changed=false;
1364   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1365     {
1366       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1367         {
1368           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1369           changed=true;
1370         }
1371       else
1372         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373       *connINewPtr=connNew->getNumberOfTuples();
1374     }
1375   if(changed)
1376     setConnectivity(connNew,connINew,false);
1377 }
1378
1379 /*!
1380  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382  * the format of the returned DataArrayIdType instance.
1383  *
1384  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1386  */
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1388 {
1389   checkConnectivityFullyDefined();
1390   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392   std::vector<bool> retS(maxElt,false);
1393   computeNodeIdsAlg(retS);
1394   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1395 }
1396
1397 /*!
1398  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1400  */
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1402 {
1403   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404            nbOfCells=getNumberOfCells();
1405   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406   for(mcIdType i=0;i<nbOfCells;i++)
1407     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1408       if(conn[j]>=0)
1409         {
1410           if(conn[j]<nbOfNodes)
1411             nodeIdsInUse[conn[j]]=true;
1412           else
1413             {
1414               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1415               throw INTERP_KERNEL::Exception(oss.str());
1416             }
1417         }
1418 }
1419
1420 /// @cond INTERNAL
1421
1422 struct MEDCouplingAccVisit
1423 {
1424   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426   mcIdType _new_nb_of_nodes;
1427 };
1428
1429 /// @endcond
1430
1431 /*!
1432  * Finds nodes not used in any cell and returns an array giving a new id to every node
1433  * by excluding the unused nodes, for which the array holds -1. The result array is
1434  * a mapping in "Old to New" mode.
1435  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438  *          if the node is unused or a new id else. The caller is to delete this
1439  *          array using decrRef() as it is no more needed.
1440  *  \throw If the coordinates array is not set.
1441  *  \throw If the nodal connectivity of cells is not defined.
1442  *  \throw If the nodal connectivity includes an invalid id.
1443  *
1444  *  \if ENABLE_EXAMPLES
1445  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1447  *  \endif
1448  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1449  */
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1451 {
1452   nbrOfNodesInUse=-1;
1453   mcIdType nbOfNodes(getNumberOfNodes());
1454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455   ret->alloc(nbOfNodes,1);
1456   mcIdType *traducer=ret->getPointer();
1457   std::fill(traducer,traducer+nbOfNodes,-1);
1458   mcIdType nbOfCells=getNumberOfCells();
1459   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460   const mcIdType *conn=_nodal_connec->getConstPointer();
1461   for(mcIdType i=0;i<nbOfCells;i++)
1462     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1463       if(conn[j]>=0)
1464         {
1465           if(conn[j]<nbOfNodes)
1466             traducer[conn[j]]=1;
1467           else
1468             {
1469               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1470               throw INTERP_KERNEL::Exception(oss.str());
1471             }
1472         }
1473   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1475   return ret.retn();
1476 }
1477
1478 /*!
1479  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480  * For each cell in \b this the number of nodes constituting cell is computed.
1481  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482  * So for pohyhedrons some nodes can be counted several times in the returned result.
1483  *
1484  * \return a newly allocated array
1485  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1486  */
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1488 {
1489   checkConnectivityFullyDefined();
1490   mcIdType nbOfCells=getNumberOfCells();
1491   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492   ret->alloc(nbOfCells,1);
1493   mcIdType *retPtr=ret->getPointer();
1494   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1497     {
1498       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499         *retPtr=connI[i+1]-connI[i]-1;
1500       else
1501         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1502     }
1503   return ret.retn();
1504 }
1505
1506 /*!
1507  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1509  *
1510  * \return DataArrayIdType * - new object to be deallocated by the caller.
1511  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1512  */
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1514 {
1515   checkConnectivityFullyDefined();
1516   mcIdType nbOfCells=getNumberOfCells();
1517   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518   ret->alloc(nbOfCells,1);
1519   mcIdType *retPtr=ret->getPointer();
1520   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1523     {
1524       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526         *retPtr=ToIdType(s.size());
1527       else
1528         {
1529           s.erase(-1);
1530           *retPtr=ToIdType(s.size());
1531         }
1532     }
1533   return ret.retn();
1534 }
1535
1536 /*!
1537  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1539  *
1540  * \return a newly allocated array
1541  */
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1543 {
1544   checkConnectivityFullyDefined();
1545   mcIdType nbOfCells=getNumberOfCells();
1546   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547   ret->alloc(nbOfCells,1);
1548   mcIdType *retPtr=ret->getPointer();
1549   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1552     {
1553       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1555     }
1556   return ret.retn();
1557 }
1558
1559 /*!
1560  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562  * array mean that the corresponding old node is no more used.
1563  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564  *           this->getNumberOfNodes() before call of this method. The caller is to
1565  *           delete this array using decrRef() as it is no more needed.
1566  *  \throw If the coordinates array is not set.
1567  *  \throw If the nodal connectivity of cells is not defined.
1568  *  \throw If the nodal connectivity includes an invalid id.
1569  *  \sa areAllNodesFetched
1570  *
1571  *  \if ENABLE_EXAMPLES
1572  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1574  *  \endif
1575  */
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1577 {
1578   return MEDCouplingPointSet::zipCoordsTraducer();
1579 }
1580
1581 /*!
1582  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1584  */
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1586 {
1587   switch(compType)
1588   {
1589     case 0:
1590       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1591     case 1:
1592       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1593     case 2:
1594       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1595     case 3:
1596       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1597     case 7:
1598       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1599   }
1600   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1610   return 0;
1611 }
1612
1613 /*!
1614  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1615  */
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1617 {
1618   mcIdType sz=connI[cell1+1]-connI[cell1];
1619   if(sz==connI[cell2+1]-connI[cell2])
1620     {
1621       if(conn[connI[cell1]]==conn[connI[cell2]])
1622         {
1623           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624           unsigned dim=cm.getDimension();
1625           if(dim!=3)
1626             {
1627               if(dim!=1)
1628                 {
1629                   mcIdType sz1=2*(sz-1);
1630                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634                   return work!=tmp+sz1?1:0;
1635                 }
1636               else
1637                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1638             }
1639           else
1640             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1641         }
1642     }
1643   return 0;
1644 }
1645
1646 /*!
1647  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1648  */
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1650 {
1651   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1652     {
1653       if(conn[connI[cell1]]==conn[connI[cell2]])
1654         {
1655           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1657           return s1==s2?1:0;
1658         }
1659     }
1660   return 0;
1661 }
1662
1663 /*!
1664  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1665  */
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1667 {
1668   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1669     {
1670       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1672       return s1==s2?1:0;
1673     }
1674   return 0;
1675 }
1676
1677 /*!
1678  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1679  */
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1681 {
1682   mcIdType sz=connI[cell1+1]-connI[cell1];
1683   if(sz==connI[cell2+1]-connI[cell2])
1684     {
1685       if(conn[connI[cell1]]==conn[connI[cell2]])
1686         {
1687           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688           unsigned dim=cm.getDimension();
1689           if(dim!=3)
1690             {
1691               if(dim!=1)
1692                 {
1693                   mcIdType sz1=2*(sz-1);
1694                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1698                   if(work!=tmp+sz1)
1699                     return 1;
1700                   else
1701                     {
1702                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1705                         return 2;
1706                       else
1707                         return 0;
1708                     }
1709                 }
1710               else
1711                 {//case of SEG2 and SEG3
1712                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1713                     return 1;
1714                   if(!cm.isQuadratic())
1715                     {
1716                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1719                         return 2;
1720                       return 0;
1721                     }
1722                   else
1723                     {
1724                       if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1725                         return 2;
1726                       return 0;
1727                     }
1728                 }
1729             }
1730           else
1731             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 /*!
1739  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741  * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743  * This method is time consuming.
1744  *
1745  * \param [in] compType input specifying the technique used to compare cells each other.
1746  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750  * can be used for users not sensitive to orientation of cell
1751  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1754  *
1755  */
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1757 {
1758   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759   getReverseNodalConnectivity(revNodal,revNodalI);
1760   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1761 }
1762
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1765 {
1766   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771   std::vector<bool> isFetched(nbOfCells,false);
1772   if(startCellId==0)
1773     {
1774       for(mcIdType i=startCellId;i<nbOfCells;i++)
1775         {
1776           if(!isFetched[i])
1777             {
1778               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779               std::vector<mcIdType> v,v2;
1780               if(connOfNode!=connPtr+connIPtr[i+1])
1781                 {
1782                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1784                   connOfNode++;
1785                 }
1786               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1787                 if(*connOfNode>=0)
1788                   {
1789                     v=v2;
1790                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792                     v2.resize(std::distance(v2.begin(),it));
1793                   }
1794               if(v2.size()>1)
1795                 {
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType pos=commonCellsI->back();
1799                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   else
1808     {
1809       for(mcIdType i=startCellId;i<nbOfCells;i++)
1810         {
1811           if(!isFetched[i])
1812             {
1813               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815               std::vector<mcIdType> v,v2;
1816               if(connOfNode!=connPtr+connIPtr[i+1])
1817                 {
1818                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1819                   connOfNode++;
1820                 }
1821               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1822                 if(*connOfNode>=0)
1823                   {
1824                     v=v2;
1825                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826                     v2.resize(std::distance(v2.begin(),it));
1827                   }
1828               // v2 contains now candidates. Problem candidates are sorted using id rank.
1829               if(v2.size()>1)
1830                 {
1831                   if(v2[0]!=i)
1832                   {
1833                     auto it(std::find(v2.begin(),v2.end(),i));
1834                     std::swap(*v2.begin(),*it);
1835                   }
1836                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1837                     {
1838                       mcIdType newPos(commonCells->getNumberOfTuples());
1839                       mcIdType pos(commonCellsI->back());
1840                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841                       commonCellsI->pushBackSilent(newPos);
1842                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843                         isFetched[*it]=true;
1844                     }
1845                 }
1846             }
1847         }
1848     }
1849   commonCellsArr=commonCells.retn();
1850   commonCellsIArr=commonCellsI.retn();
1851 }
1852
1853 /*!
1854  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856  * than \a this->getNumberOfCells() in the returned array means that there is no
1857  * corresponding cell in \a this mesh.
1858  * It is expected that \a this and \a other meshes share the same node coordinates
1859  * array, if it is not so an exception is thrown.
1860  *  \param [in] other - the mesh to compare with.
1861  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1862  *         valid values [0,1,2], see zipConnectivityTraducer().
1863  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1865  *         values. The caller is to delete this array using
1866  *         decrRef() as it is no more needed.
1867  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1868  *         mesh.
1869  *
1870  *  \if ENABLE_EXAMPLES
1871  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1873  *  \endif
1874  *  \sa checkDeepEquivalOnSameNodesWith()
1875  *  \sa checkGeoEquivalWith()
1876  */
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1878 {
1879   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880   mcIdType nbOfCells=getNumberOfCells();
1881   static const int possibleCompType[]={0,1,2};
1882   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1883     {
1884       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1886       oss << " !";
1887       throw INTERP_KERNEL::Exception(oss.str());
1888     }
1889   //
1890   if(other->getNumberOfCells()==0)
1891   {
1892     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1893     return true;
1894   }
1895   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898   mcIdType newNbOfCells=-1;
1899   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901   mcIdType maxPart(p0->getMaxValueInArray());
1902   bool ret(maxPart==newNbOfCells-1);
1903   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904   // fill p1 array in case of presence of cells in other not in this
1905   mcIdType *pt(p1->getPointer());
1906   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1907     pt[i+1] = i+1;
1908   //
1909   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1911   arr = p2.retn();
1912   return ret;
1913 }
1914
1915 /*!
1916  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917  * This method tries to determine if \b other is fully included in \b this.
1918  * The main difference is that this method is not expected to throw exception.
1919  * This method has two outputs :
1920  *
1921  * \param other other mesh
1922  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1924  */
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1926 {
1927   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928   DataArrayIdType *commonCells=0,*commonCellsI=0;
1929   mcIdType thisNbCells=getNumberOfCells();
1930   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933   mcIdType otherNbCells=other->getNumberOfCells();
1934   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935   arr2->alloc(otherNbCells,1);
1936   arr2->fillWithZero();
1937   mcIdType *arr2Ptr=arr2->getPointer();
1938   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939   for(mcIdType i=0;i<nbOfCommon;i++)
1940     {
1941       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942       if(start<thisNbCells)
1943         {
1944           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1945             {
1946               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947               mcIdType val=std::abs(commonCellsPtr[j])-1;
1948               if(val>=thisNbCells)
1949                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1950             }
1951         }
1952     }
1953   arr2->setName(other->getName());
1954   if(arr2->presenceOfValue(0))
1955     return false;
1956   arr=arr2.retn();
1957   return true;
1958 }
1959
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1961 {
1962   if(!other)
1963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1965   if(!otherC)
1966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967   std::vector<const MEDCouplingUMesh *> ms(2);
1968   ms[0]=this;
1969   ms[1]=otherC;
1970   return MergeUMeshesOnSameCoords(ms);
1971 }
1972
1973 /*!
1974  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976  * cellIds is not given explicitly but by a range python like.
1977  *
1978  * \param start starting ID
1979  * \param end end ID (excluded)
1980  * \param step step size
1981  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982  * \return a newly allocated
1983  *
1984  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1986  */
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1988 {
1989   if(getMeshDimension()!=-1)
1990     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1991   else
1992     {
1993       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1994       if(newNbOfCells!=1)
1995         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1996       if(start!=0)
1997         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1998       incrRef();
1999       return const_cast<MEDCouplingUMesh *>(this);
2000     }
2001 }
2002
2003 /*!
2004  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005  * The result mesh shares or not the node coordinates array with \a this mesh depending
2006  * on \a keepCoords parameter.
2007  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008  *           to write this mesh to the MED file, its cells must be sorted using
2009  *           sortCellsInMEDFileFrmt().
2010  *  \param [in] begin - an array of cell ids to include to the new mesh.
2011  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2014  *         by calling zipCoords().
2015  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016  *         to delete this mesh using decrRef() as it is no more needed.
2017  *  \throw If the coordinates array is not set.
2018  *  \throw If the nodal connectivity of cells is not defined.
2019  *  \throw If any cell id in the array \a begin is not valid.
2020  *
2021  *  \if ENABLE_EXAMPLES
2022  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2024  *  \endif
2025  */
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2027 {
2028   if(getMeshDimension()!=-1)
2029     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2030   else
2031     {
2032       if(end-begin!=1)
2033         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2034       if(begin[0]!=0)
2035         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2036       incrRef();
2037       return const_cast<MEDCouplingUMesh *>(this);
2038     }
2039 }
2040
2041 /*!
2042  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2043  *
2044  * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046  * The number of cells of \b this will remain the same with this method.
2047  *
2048  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050  * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2052  */
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2054 {
2055   checkConnectivityFullyDefined();
2056   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2060     {
2061       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063       throw INTERP_KERNEL::Exception(oss.str());
2064     }
2065   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069       throw INTERP_KERNEL::Exception(oss.str());
2070     }
2071   mcIdType nbOfCells(getNumberOfCells());
2072   bool easyAssign(true);
2073   const mcIdType *connI(_nodal_connec_index->begin());
2074   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2076     {
2077       if(*it>=0 && *it<nbOfCells)
2078         {
2079           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2080         }
2081       else
2082         {
2083           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084           throw INTERP_KERNEL::Exception(oss.str());
2085         }
2086     }
2087   if(easyAssign)
2088     {
2089       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2090       computeTypes();
2091     }
2092   else
2093     {
2094       DataArrayIdType *arrOut=0,*arrIOut=0;
2095       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2096                                                arrOut,arrIOut);
2097       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098       setConnectivity(arrOut,arrIOut,true);
2099     }
2100 }
2101
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2103 {
2104   checkConnectivityFullyDefined();
2105   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2109     {
2110       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112       throw INTERP_KERNEL::Exception(oss.str());
2113     }
2114   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118       throw INTERP_KERNEL::Exception(oss.str());
2119     }
2120   mcIdType nbOfCells=getNumberOfCells();
2121   bool easyAssign=true;
2122   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2124   mcIdType it=start;
2125   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2126     {
2127       if(it>=0 && it<nbOfCells)
2128         {
2129           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2130         }
2131       else
2132         {
2133           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134           throw INTERP_KERNEL::Exception(oss.str());
2135         }
2136     }
2137   if(easyAssign)
2138     {
2139       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2140       computeTypes();
2141     }
2142   else
2143     {
2144       DataArrayIdType *arrOut=0,*arrIOut=0;
2145       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2146                                                 arrOut,arrIOut);
2147       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148       setConnectivity(arrOut,arrIOut,true);
2149     }
2150 }
2151
2152
2153 /*!
2154  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155  * this->getMeshDimension(), that bound some cells of \a this mesh.
2156  * The cells of lower dimension to include to the result mesh are selected basing on
2157  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160  * created mesh shares the node coordinates array with \a this mesh.
2161  *  \param [in] begin - the array of node ids.
2162  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164  *         array \a begin are added, else cells whose any node is in the
2165  *         array \a begin are added.
2166  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167  *         to delete this mesh using decrRef() as it is no more needed.
2168  *  \throw If the coordinates array is not set.
2169  *  \throw If the nodal connectivity of cells is not defined.
2170  *  \throw If any node id in \a begin is not valid.
2171  *
2172  *  \if ENABLE_EXAMPLES
2173  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2175  *  \endif
2176  */
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2178 {
2179   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2184 }
2185
2186 /*!
2187  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2191  *         by calling zipCoords().
2192  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193  *         to delete this mesh using decrRef() as it is no more needed.
2194  *  \throw If the coordinates array is not set.
2195  *  \throw If the nodal connectivity of cells is not defined.
2196  *
2197  *  \if ENABLE_EXAMPLES
2198  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2200  *  \endif
2201  */
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2203 {
2204   DataArrayIdType *desc=DataArrayIdType::New();
2205   DataArrayIdType *descIndx=DataArrayIdType::New();
2206   DataArrayIdType *revDesc=DataArrayIdType::New();
2207   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2208   //
2209   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2210   revDesc->decrRef();
2211   desc->decrRef();
2212   descIndx->decrRef();
2213   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215   std::vector<mcIdType> boundaryCells;
2216   for(mcIdType i=0;i<nbOfCells;i++)
2217     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218       boundaryCells.push_back(i);
2219   revDescIndx->decrRef();
2220   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2221   return ret;
2222 }
2223
2224 /*!
2225  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2228  */
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2230 {
2231   checkFullyDefined();
2232   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2236   //
2237   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2239   //
2240   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242   const mcIdType *revDescPtr=revDesc->getConstPointer();
2243   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244   mcIdType nbOfCells=getNumberOfCells();
2245   std::vector<bool> ret1(nbOfCells,false);
2246   mcIdType sz=0;
2247   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2250   //
2251   DataArrayIdType *ret2=DataArrayIdType::New();
2252   ret2->alloc(sz,1);
2253   mcIdType *ret2Ptr=ret2->getPointer();
2254   sz=0;
2255   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2256     if(*it)
2257       *ret2Ptr++=sz;
2258   ret2->setName("BoundaryCells");
2259   return ret2;
2260 }
2261
2262 /*!
2263  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2267  *
2268  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269  * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2270  * equals a cell in \b otherDimM1OnSameCoords.
2271  *
2272  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2274  *
2275  * \param [in] otherDimM1OnSameCoords other mesh
2276  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277  * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2278  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2279  */
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2281 {
2282   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284   checkConnectivityFullyDefined();
2285   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294   DataArrayIdType *idsOtherInConsti=0;
2295   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2297   if(!b)
2298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299   std::set<mcIdType> s1;
2300   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303   s1arr_renum1->sort();
2304   cellIdsRk0=s0arr.retn();
2305   //cellIdsRk1=s_renum1.retn();
2306   cellIdsRk1=s1arr_renum1.retn();
2307 }
2308
2309 /*!
2310  * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2311  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2312  *
2313  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2314  */
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2316 {
2317   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2321   //
2322   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323   revDesc=0; desc=0; descIndx=0;
2324   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2327 }
2328
2329 /*!
2330  * Finds nodes lying on the boundary of \a this mesh.
2331  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332  *          nodes. The caller is to delete this array using decrRef() as it is no
2333  *          more needed.
2334  *  \throw If the coordinates array is not set.
2335  *  \throw If the nodal connectivity of cells is node defined.
2336  *
2337  *  \if ENABLE_EXAMPLES
2338  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2340  *  \endif
2341  */
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2343 {
2344   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345   return skin->computeFetchedNodeIds();
2346 }
2347
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2349 {
2350   incrRef();
2351   return const_cast<MEDCouplingUMesh *>(this);
2352 }
2353
2354 /*!
2355  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2358  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2359  * When the set of node ids \b nodeIdsToDuplicate is computed, cell ids in \b this is searched so that their connectivity includes at least 1 node in \b nodeIdsToDuplicate.
2360  *
2361  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2362  *             parameter is altered during the call.
2363  * \return node ids which need to be duplicated following the algorithm explained above.
2364  *
2365  */
2366 DataArrayIdType* MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords) const
2367 {
2368   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2369   // which mimicks the C++
2370   using DAInt = MCAuto<DataArrayIdType>;
2371   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2372
2373   checkFullyDefined();
2374   otherDimM1OnSameCoords.checkFullyDefined();
2375   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2376     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2377   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2378     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2379
2380   // Checking star-shaped M1 group:
2381   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2382   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2383   DAInt dsi = rdit0->deltaShiftIndex();
2384   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);  // for 2D: if a point is connected to more than 2 segs. For 3D: if a seg is connected to more than two faces.
2385   if(idsTmp0->getNumberOfTuples())
2386     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2387   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2388
2389   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2390   // ie nodes belonging to the boundary "cells" (might be points) of M1
2391   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2392   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2393   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2394   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2395   dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2396   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2397   dsi = rdit0->deltaShiftIndex();  rdit0=0;
2398   DAInt boundSegs = dsi->findIdsEqual(1);  dsi = 0; // boundary segs/faces of the M0 mesh
2399   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2400   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2401   // In 3D, some points on the boundary of M0 will NOT be duplicated (where as in 2D, points on the boundary of M0 are always duplicated)
2402   // Think of a partial (plane) crack in a cube: the points at the tip of the crack and not located inside the volume of the cube are not duplicated
2403   // although they are technically on the skin of the cube.
2404   DAInt notDup = 0;
2405   if (getMeshDimension() == 3)
2406     {
2407       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2408       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2409       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2410       DataArrayIdType * corresp=0;
2411       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2412       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2413       // In the cube example above, this is a U shape polyline.
2414       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2415       corresp->decrRef();
2416       if (validIds->getNumberOfTuples())
2417         {
2418           // Build the set of segments which are: in the desc mesh of the skin of the 3D mesh (M0) **and** in the desc mesh of the M1 group:
2419           // (the U-shaped polyline described above)
2420           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2421           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2422           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2423           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2424
2425           // Specific logic to handle singular points :
2426           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2427           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2428           //   algorithm would be duplicating too much ...
2429           // This is a costly algorithm so only go into it if a simple (non sufficient) criteria is met: a node connected to more than 3 segs in meshM2:
2430           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2431           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2432           dnu1=0;dnu2=0;dnu3=0;
2433           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2434           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2435           if (singPoints->getNumberOfTuples())
2436             {
2437               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2438               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2439               // should not be duplicated
2440               //    1. Extract N D cells touching U-shape line:
2441               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2442               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2443               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2444               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2445               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2446               DataArrayIdType *idsOfM1BNt;
2447               mAroundBNDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1BNt);
2448               DAInt idsOfM1BN(idsOfM1BNt);
2449               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2450               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2451               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2452               for(const auto& v: *idsOfM1BN)
2453                 {
2454                   if (v >= nCellsDesc)    // Keep valid match only
2455                     continue;
2456                   mcIdType idx0 = revDescIBNP[v];
2457                   // Keep the two cells on either side of the face v of M1:
2458                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2459                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2460                 }
2461               //    3. Build complement
2462               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2463               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2464               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2465               DAInt inters = boundNodes->buildIntersection(nod3);
2466               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2467             }
2468           notDup = xtrem->buildSubstraction(fNodes1);
2469         }
2470       else  // if (validIds-> ...)
2471         notDup = xtrem->buildSubstraction(fNodes);
2472     }
2473   else  // if (3D ...)
2474     notDup = xtrem->buildSubstraction(fNodes);
2475
2476   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2477   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2478   return dupl.retn();
2479 }
2480
2481
2482 /*!
2483  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2484  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2485  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2486  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2487  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2488  *
2489  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2490  *             parameter is altered during the call.
2491  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2492  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2493  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2494  * \param [out] cellIdsNotModified cell ids in \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2495  *
2496  */
2497 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2498                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2499 {
2500   // DEBUG NOTE: in case of issue with the algorithm in this method, see Python script in resources/dev
2501   // which mimicks the C++
2502   using DAInt = MCAuto<DataArrayIdType>;
2503   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2504
2505   checkFullyDefined();
2506   otherDimM1OnSameCoords.checkFullyDefined();
2507   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2508     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2509   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2510     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2511
2512   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2513
2514   //
2515   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2516   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2517   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2518   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2519
2520   // Extract now all N D cells which have a complete face in touch with the group:
2521   //   1. Identify cells of M1 group in sub-mesh mAroundGrp
2522   DataArrayIdType *idsOfM1t;
2523   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2524   DAInt idsOfM1Large(idsOfM1t);
2525   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2526   DAInt idsStrict = DataArrayIdType::New(); idsStrict->alloc(0,1);
2527   //  2. Build map giving for each cell ID in mAroundGrp (not in mAroundGrpLarge) the corresponding cell
2528   //     ID on the other side of the crack:
2529   std::map<mcIdType, mcIdType> toOtherSide, pos;
2530   mcIdType cnt = 0;
2531   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2532   for(const auto& v: *idsOfM1Large)
2533     {
2534       if (v >= nL)    // Keep valid match only
2535         continue;
2536       mcIdType idx0 = revDescILP[v];
2537       // Keep the two cells on either side of the face v of M1:
2538       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2539       DAInt t1=idsStrict->findIdsEqual(c1), t2=idsStrict->findIdsEqual(c2);
2540
2541       if (!t1->getNumberOfTuples())
2542         {  pos[c1] = cnt++; idsStrict->pushBackSilent(c1);   }
2543       if (!t2->getNumberOfTuples())
2544         {  pos[c2] = cnt++; idsStrict->pushBackSilent(c2);   }
2545
2546       mcIdType k1 = pos[c1], k2=pos[c2];
2547       toOtherSide[k1] = k2;
2548       toOtherSide[k2] = k1;
2549     }
2550
2551   DAInt cellsAroundGroup = cellsAroundGroupLarge->selectByTupleId(idsStrict->begin(), idsStrict->end());
2552   MCUMesh mAroundGrp = static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(), cellsAroundGroup->end(), true));
2553   mcIdType nCells=cellsAroundGroup->getNumberOfTuples(), nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2554   DAInt desc=DataArrayIdType::New(),descI=DataArrayIdType::New(),revDesc=DataArrayIdType::New(),revDescI=DataArrayIdType::New();  
2555   MCUMesh mArGrpDesc=mAroundGrp->buildDescendingConnectivity(desc,descI,revDesc,revDescI);
2556   DataArrayIdType *idsOfM1t2;
2557   mArGrpDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t2);  // TODO can we avoid recomputation here?
2558   DAInt idsOfM1(idsOfM1t2);
2559
2560   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2561   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2562   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2563   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1->begin(), idsOfM1->end(),desc,descI);
2564   //     Compute the neighbor of each cell in mAroundGrp, taking into account the broken link above. Two
2565   //     cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2566   DataArrayIdType *neight=0, *neighIt=0;
2567   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc,descI,revDesc,revDescI, neight, neighIt);
2568   DAInt neigh(neight), neighI(neighIt);
2569
2570   // For each initial connex part of the M1 mesh (or said differently for each independent crack):
2571   mcIdType seed=0, nIter=0;
2572   mcIdType nIterMax = nCells+1; // Safety net for the loop
2573   DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells,1);
2574   mcIdType* hitCellsP = hitCells->rwBegin();
2575   hitCells->fillWithValue(0);  // 0 : not hit, +x: one side of the crack, -x: other side of the crack, with 'x' the index of the connex component
2576   mcIdType PING_FULL, PONG_FULL;
2577   mcIdType MAX_CP = 10000;  // the choices below assume we won't have more than 10000 different connex parts ...
2578   mcIdType PING_FULL_init = 0, PING_PART = MAX_CP;
2579   mcIdType PONG_FULL_init = 0, PONG_PART = -MAX_CP;
2580   cnt=0;
2581   while (nIter < nIterMax)
2582     {
2583       DAInt t = hitCells->findIdsEqual(0);
2584       if(!t->getNumberOfTuples())
2585         break;
2586       mcIdType seed = t->getIJ(0,0);
2587       bool done = false;
2588       cnt++;
2589       PING_FULL = PING_FULL_init+cnt;
2590       PONG_FULL = PONG_FULL_init-cnt;
2591       // while the connex bits in correspondance on either side of the crack are not fully covered
2592       while(!done && nIter < nIterMax)  // Start of the ping-pong
2593         {
2594           nIter++;
2595           // Identify connex zone around the seed - this zone corresponds to some cells on the other side
2596           // of the crack that might extend further away. So we will need to compute spread zone on the other side
2597           // too ... and this process can repeat, hence the "ping-pong" logic.
2598           mcIdType dnu;
2599           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh,neighI, -1, dnu);
2600           done = true;
2601           for(const mcIdType& s: *spreadZone)
2602             {
2603               hitCellsP[s] = PING_FULL;
2604               const auto& it = toOtherSide.find(s);
2605               if (it != toOtherSide.end())
2606                 {
2607                   mcIdType other = it->second;
2608                   if (hitCellsP[other] != PONG_FULL)
2609                     {
2610                       // On the other side of the crack we hit a cell which was not fully covered previously by the 
2611                       // ComputeSpreadZone process, so we are not done yet, ComputeSreadZone will need to be applied there
2612                       done = false;
2613                       hitCellsP[other] = PONG_PART;
2614                       //  Compute next seed, i.e. a cell on the other side of the crack
2615                       seed = other;
2616                     }
2617                 }
2618             }
2619           if (done)
2620             {
2621               // we might have several disjoint PONG parts in front of a single PING connex part:
2622               DAInt idsPong = hitCells->findIdsEqual(PONG_PART);
2623               if (idsPong->getNumberOfTuples())
2624                 {
2625                   seed = idsPong->getIJ(0,0);
2626                   done = false;
2627                 }
2628               continue;  // continue without switching side (or break if 'done' remains false)
2629             }
2630           else
2631             {
2632               // Go to the other side
2633               std::swap(PING_FULL, PONG_FULL);
2634               std::swap(PING_PART, PONG_PART);
2635             }
2636         } // while (!done ...)
2637       DAInt nonHitCells = hitCells->findIdsEqual(0);
2638       if (nonHitCells->getNumberOfTuples())
2639         seed = nonHitCells->getIJ(0,0);
2640       else
2641         break;
2642     } // while (nIter < nIterMax ...
2643   if (nIter >= nIterMax)
2644     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Too many iterations - should not happen");
2645
2646   // Now we have handled all N D cells which have a face touching the M1 group. It remains the cells
2647   // which are just touching the group by one (or several) node(s) (see for example testBuildInnerBoundaryAlongM1Group4)
2648   // All those cells are in direct contact with a cell which is either PING_FULL or PONG_FULL
2649   // So first reproject the PING/PONG info onto mAroundGrpLarge:
2650   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2651   hitCellsLarge->fillWithValue(0);
2652   mcIdType *hitCellsLargeP=hitCellsLarge->rwBegin(), tt=0;
2653   for(const auto &i: *idsStrict)
2654     { hitCellsLargeP[i] = hitCellsP[tt++]; }
2655   DAInt nonHitCells = hitCellsLarge->findIdsEqual(0);
2656   // Neighbor information in mAroundGrpLarge:
2657   DataArrayIdType *neighLt=0, *neighILt=0;
2658   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descL,descIL,revDescL,revDescIL, neighLt, neighILt);
2659   DAInt neighL(neighLt), neighIL(neighILt);
2660   const mcIdType *neighILP=neighIL->begin(), *neighLP=neighL->begin();
2661   for(const auto& c : *nonHitCells)
2662     {
2663       mcIdType cnt00 = neighILP[c];
2664       for (const mcIdType *n=neighLP+cnt00; cnt00 < neighILP[c+1]; n++, cnt00++)
2665         {
2666           mcIdType neighVal = hitCellsLargeP[*n];
2667           if (neighVal != 0 && std::abs(neighVal) < MAX_CP)  // (@test_T0) second part of the test to skip cells being assigned and target only cells assigned in the first part of the algo above
2668             {
2669               mcIdType currVal = hitCellsLargeP[c];
2670               if (currVal != 0)   // Several neighbors have a candidate number
2671                 {
2672                   // Unfortunately in some weird cases (see testBuildInnerBoundary8) a cell in mAroundGrpLarge
2673                   // might have as neighbor two conflicting spread zone ...
2674                   if (currVal*neighVal < 0)
2675                     {
2676                       // If we arrive here, the cell was already assigned a number and we found a neighbor with
2677                       // a different sign ... we must swap the whole spread zone!!
2678                       DAInt ids1 = hitCellsLarge->findIdsEqual(neighVal), ids1b = hitCellsLarge->findIdsEqual(-neighVal);
2679                       DAInt ids2 = hitCellsLarge->findIdsEqual(MAX_CP*neighVal), ids2b = hitCellsLarge->findIdsEqual(-MAX_CP*neighVal);
2680                       // A nice little lambda to multiply part of a DAInt by -1 ...
2681                       auto mul_part_min1 = [hitCellsLargeP](const DAInt& ids) { for(const auto& i: *ids) hitCellsLargeP[i] *= -1; };
2682                       mul_part_min1(ids1);
2683                       mul_part_min1(ids1b);
2684                       mul_part_min1(ids2);
2685                       mul_part_min1(ids2b);
2686                     }
2687                 }
2688               else  // First assignation
2689                 hitCellsLargeP[c] = MAX_CP*neighVal;  // Same sign, but different value to preserve PING_FULL and PONG_FULL
2690             }
2691         }
2692     }
2693   DAInt cellsRet1 = hitCellsLarge->findIdsInRange(1,MAX_CP*MAX_CP);   // Positive spread zone number
2694   DAInt cellsRet2 = hitCellsLarge->findIdsInRange(-MAX_CP*MAX_CP, 0); // Negative spread zone number
2695
2696   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2697     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2698   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2699   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2700   //
2701   cellIdsNeededToBeRenum=cellsRet1.retn();
2702   cellIdsNotModified=cellsRet2.retn();
2703 }
2704
2705 /*!
2706  * This method operates a modification of the connectivity and coords in \b this.
2707  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2708  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2709  * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2710  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2711  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2712  *
2713  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2714  *
2715  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2716  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2717  */
2718 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2719 {
2720   mcIdType nbOfNodes=getNumberOfNodes();
2721   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2722   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2723 }
2724
2725 /*!
2726  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2727  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2728  *
2729  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2730  *
2731  * \sa renumberNodesInConn
2732  */
2733 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2734 {
2735   checkConnectivityFullyDefined();
2736   mcIdType *conn(getNodalConnectivity()->getPointer());
2737   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2738   mcIdType nbOfCells=getNumberOfCells();
2739   for(mcIdType i=0;i<nbOfCells;i++)
2740     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2741       {
2742         mcIdType& node=conn[iconn];
2743         if(node>=0)//avoid polyhedron separator
2744           {
2745             node+=offset;
2746           }
2747       }
2748   _nodal_connec->declareAsNew();
2749   updateTime();
2750 }
2751
2752 /*!
2753  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2754  *  of array. This method is dedicated for renumbering from a big set of nodes the a tiny set of nodes which is the case during extraction
2755  *  of a big mesh.
2756  */
2757 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2758 {
2759   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2760 }
2761
2762 /*!
2763  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2764  *  of array. This method is dedicated for renumbering from a big set of nodes the a tiny set of nodes which is the case during extraction
2765  *  of a big mesh.
2766  */
2767 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2768 {
2769   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2770 }
2771
2772 /*!
2773  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2774  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2775  * This method is a generalization of shiftNodeNumbersInConn().
2776  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2777  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2778  *         this->getNumberOfNodes(), in "Old to New" mode.
2779  *         See \ref numbering for more info on renumbering modes.
2780  *  \throw If the nodal connectivity of cells is not defined.
2781  *
2782  *  \if ENABLE_EXAMPLES
2783  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2784  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2785  *  \endif
2786  */
2787 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2788 {
2789   checkConnectivityFullyDefined();
2790   mcIdType *conn=getNodalConnectivity()->getPointer();
2791   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2792   mcIdType nbOfCells=getNumberOfCells();
2793   for(mcIdType i=0;i<nbOfCells;i++)
2794     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2795       {
2796         mcIdType& node=conn[iconn];
2797         if(node>=0)//avoid polyhedron separator
2798           {
2799             node=newNodeNumbersO2N[node];
2800           }
2801       }
2802   _nodal_connec->declareAsNew();
2803   updateTime();
2804 }
2805
2806 /*!
2807  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2808  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2809  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2810  *
2811  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2812  */
2813 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2814 {
2815   checkConnectivityFullyDefined();
2816   mcIdType *conn=getNodalConnectivity()->getPointer();
2817   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2818   mcIdType nbOfCells=getNumberOfCells();
2819   for(mcIdType i=0;i<nbOfCells;i++)
2820     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2821       {
2822         mcIdType& node=conn[iconn];
2823         if(node>=0)//avoid polyhedron separator
2824           {
2825             node+=delta;
2826           }
2827       }
2828   _nodal_connec->declareAsNew();
2829   updateTime();
2830 }
2831
2832 /*!
2833  * This method operates a modification of the connectivity in \b this.
2834  * Coordinates are \b NOT considered here and will remain unchanged by this method. this->_coords can ever been null for the needs of this method.
2835  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2836  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2837  * More explicitly the renumber array in nodes is not explicitly given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2838  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2839  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2840  *
2841  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2842  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2843  *
2844  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2845  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2846  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2847  */
2848 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2849 {
2850   checkConnectivityFullyDefined();
2851   std::map<mcIdType,mcIdType> m;
2852   mcIdType val=offset;
2853   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2854     m[*work]=val;
2855   mcIdType *conn=getNodalConnectivity()->getPointer();
2856   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2857   mcIdType nbOfCells=getNumberOfCells();
2858   for(mcIdType i=0;i<nbOfCells;i++)
2859     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2860       {
2861         mcIdType& node=conn[iconn];
2862         if(node>=0)//avoid polyhedron separator
2863           {
2864             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2865             if(it!=m.end())
2866               node=(*it).second;
2867           }
2868       }
2869   updateTime();
2870 }
2871
2872 /*!
2873  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2874  *
2875  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2876  * After the call of this method the number of cells remains the same as before.
2877  *
2878  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2879  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2880  * be strictly in [0;this->getNumberOfCells()).
2881  *
2882  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2883  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2884  * should be contained in[0;this->getNumberOfCells()).
2885  *
2886  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2887  * \param check whether to check content of old2NewBg
2888  */
2889 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2890 {
2891   checkConnectivityFullyDefined();
2892   mcIdType nbCells=getNumberOfCells();
2893   const mcIdType *array=old2NewBg;
2894   if(check)
2895     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2896   //
2897   const mcIdType *conn=_nodal_connec->getConstPointer();
2898   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2899   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2900   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2901   const mcIdType *n2oPtr=n2o->begin();
2902   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2903   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2904   newConn->copyStringInfoFrom(*_nodal_connec);
2905   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2906   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2907   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2908   //
2909   mcIdType *newC=newConn->getPointer();
2910   mcIdType *newCI=newConnI->getPointer();
2911   mcIdType loc=0;
2912   newCI[0]=loc;
2913   for(mcIdType i=0;i<nbCells;i++)
2914     {
2915       mcIdType pos=n2oPtr[i];
2916       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2917       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2918       loc+=nbOfElts;
2919       newCI[i+1]=loc;
2920     }
2921   //
2922   setConnectivity(newConn,newConnI);
2923   if(check)
2924     free(const_cast<mcIdType *>(array));
2925 }
2926
2927 /*!
2928  * Finds cells whose bounding boxes intersect a given bounding box.
2929  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2930  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2931  *         zMax (if in 3D).
2932  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2933  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2934  *         extent of the bounding box of cell to produce an addition to this bounding box.
2935  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2936  *         cells. The caller is to delete this array using decrRef() as it is no more
2937  *         needed.
2938  *  \throw If the coordinates array is not set.
2939  *  \throw If the nodal connectivity of cells is not defined.
2940  *
2941  *  \if ENABLE_EXAMPLES
2942  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2943  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2944  *  \endif
2945  */
2946 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2947 {
2948   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2949   if(getMeshDimension()==-1)
2950     {
2951       elems->pushBackSilent(0);
2952       return elems.retn();
2953     }
2954   int dim=getSpaceDimension();
2955   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2956   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2957   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2958   const double* coords = getCoords()->getConstPointer();
2959   mcIdType nbOfCells=getNumberOfCells();
2960   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2961     {
2962       for (int i=0; i<dim; i++)
2963         {
2964           elem_bb[i*2]=std::numeric_limits<double>::max();
2965           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2966         }
2967
2968       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2969         {
2970           mcIdType node= conn[inode];
2971           if(node>=0)//avoid polyhedron separator
2972             {
2973               for (int idim=0; idim<dim; idim++)
2974                 {
2975                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2976                     {
2977                       elem_bb[idim*2] = coords[node*dim+idim] ;
2978                     }
2979                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2980                     {
2981                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2982                     }
2983                 }
2984             }
2985         }
2986       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2987         elems->pushBackSilent(ielem);
2988     }
2989   return elems.retn();
2990 }
2991
2992 /*!
2993  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2994  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2995  * added in 'elems' parameter.
2996  */
2997 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2998 {
2999   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
3000   if(getMeshDimension()==-1)
3001     {
3002       elems->pushBackSilent(0);
3003       return elems.retn();
3004     }
3005   int dim=getSpaceDimension();
3006   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
3007   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
3008   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
3009   const double* coords = getCoords()->getConstPointer();
3010   mcIdType nbOfCells=getNumberOfCells();
3011   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
3012     {
3013       for (int i=0; i<dim; i++)
3014         {
3015           elem_bb[i*2]=std::numeric_limits<double>::max();
3016           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
3017         }
3018
3019       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
3020         {
3021           mcIdType node= conn[inode];
3022           if(node>=0)//avoid polyhedron separator
3023             {
3024               for (int idim=0; idim<dim; idim++)
3025                 {
3026                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
3027                     {
3028                       elem_bb[idim*2] = coords[node*dim+idim] ;
3029                     }
3030                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
3031                     {
3032                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
3033                     }
3034                 }
3035             }
3036         }
3037       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
3038         elems->pushBackSilent(ielem);
3039     }
3040   return elems.retn();
3041 }
3042
3043 /*!
3044  * Returns a type of a cell by its id.
3045  *  \param [in] cellId - the id of the cell of interest.
3046  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
3047  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3048  */
3049 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
3050 {
3051   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3052   if(cellId<_nodal_connec_index->getNbOfElems()-1)
3053     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
3054   else
3055     {
3056       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
3057       throw INTERP_KERNEL::Exception(oss.str());
3058     }
3059 }
3060
3061 /*!
3062  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
3063  * This method does not throw exception if geometric type \a type is not in \a this.
3064  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
3065  * The coordinates array is not considered here.
3066  *
3067  * \param [in] type the geometric type
3068  * \return cell ids in this having geometric type \a type.
3069  */
3070 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3071 {
3072
3073   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
3074   ret->alloc(0,1);
3075   checkConnectivityFullyDefined();
3076   mcIdType nbCells=getNumberOfCells();
3077   int mdim=getMeshDimension();
3078   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
3079   if(mdim!=ToIdType(cm.getDimension()))
3080     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
3081   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3082   const mcIdType *pt=_nodal_connec->getConstPointer();
3083   for(mcIdType i=0;i<nbCells;i++)
3084     {
3085       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
3086         ret->pushBackSilent(i);
3087     }
3088   return ret.retn();
3089 }
3090
3091 /*!
3092  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
3093  */
3094 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
3095 {
3096   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3097   mcIdType nbOfCells(getNumberOfCells()),ret(0);
3098   for(mcIdType i=0;i<nbOfCells;i++)
3099     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
3100       ret++;
3101   return ret;
3102 }
3103
3104 /*!
3105  * Returns the nodal connectivity of a given cell.
3106  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3107  * all returned node ids can be used in getCoordinatesOfNode().
3108  *  \param [in] cellId - an id of the cell of interest.
3109  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3110  *         cleared before the appending.
3111  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3112  */
3113 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3114 {
3115   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3116   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3117     if(*w>=0)
3118       conn.push_back(*w);
3119 }
3120
3121 std::string MEDCouplingUMesh::simpleRepr() const
3122 {
3123   static const char msg0[]="No coordinates specified !";
3124   std::ostringstream ret;
3125   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3126   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3127   int tmpp1,tmpp2;
3128   double tt=getTime(tmpp1,tmpp2);
3129   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3130   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3131   if(_mesh_dim>=-1)
3132     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3133   else
3134     { ret << " Mesh dimension has not been set or is invalid !"; }
3135   if(_coords!=0)
3136     {
3137       const int spaceDim=getSpaceDimension();
3138       ret << spaceDim << "\nInfo attached on space dimension : ";
3139       for(int i=0;i<spaceDim;i++)
3140         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3141       ret << "\n";
3142     }
3143   else
3144     ret << msg0 << "\n";
3145   ret << "Number of nodes : ";
3146   if(_coords!=0)
3147     ret << getNumberOfNodes() << "\n";
3148   else
3149     ret << msg0 << "\n";
3150   ret << "Number of cells : ";
3151   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3152     ret << getNumberOfCells() << "\n";
3153   else
3154     ret << "No connectivity specified !" << "\n";
3155   ret << "Cell types present : ";
3156   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3157     {
3158       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3159       ret << cm.getRepr() << " ";
3160     }
3161   ret << "\n";
3162   return ret.str();
3163 }
3164
3165 std::string MEDCouplingUMesh::advancedRepr() const
3166 {
3167   std::ostringstream ret;
3168   ret << simpleRepr();
3169   ret << "\nCoordinates array : \n___________________\n\n";
3170   if(_coords)
3171     _coords->reprWithoutNameStream(ret);
3172   else
3173     ret << "No array set !\n";
3174   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3175   reprConnectivityOfThisLL(ret);
3176   return ret.str();
3177 }
3178
3179 /*!
3180  * This method returns a C++ code that is a dump of \a this.
3181  * This method will throw if this is not fully defined.
3182  */
3183 std::string MEDCouplingUMesh::cppRepr() const
3184 {
3185   static const char coordsName[]="coords";
3186   static const char connName[]="conn";
3187   static const char connIName[]="connI";
3188   checkFullyDefined();
3189   std::ostringstream ret; ret << "// coordinates" << std::endl;
3190   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3191   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3192   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3193   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3194   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3195   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3196   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3197   return ret.str();
3198 }
3199
3200 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3201 {
3202   std::ostringstream ret;
3203   reprConnectivityOfThisLL(ret);
3204   return ret.str();
3205 }
3206
3207 /*!
3208  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3209  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3210  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3211  * some algos).
3212  *
3213  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3214  * This method analyzes the 3 arrays of \a this. For each the following behaviour is done : if the array is null a newly one is created
3215  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3216  */
3217 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3218 {
3219   int mdim=getMeshDimension();
3220   if(mdim<0)
3221     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3222   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3223   MCAuto<DataArrayIdType> tmp1,tmp2;
3224   bool needToCpyCT=true;
3225   if(!_nodal_connec)
3226     {
3227       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3228       needToCpyCT=false;
3229     }
3230   else
3231     {
3232       tmp1=_nodal_connec;
3233       tmp1->incrRef();
3234     }
3235   if(!_nodal_connec_index)
3236     {
3237       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3238       needToCpyCT=false;
3239     }
3240   else
3241     {
3242       tmp2=_nodal_connec_index;
3243       tmp2->incrRef();
3244     }
3245   ret->setConnectivity(tmp1,tmp2,false);
3246   if(needToCpyCT)
3247     ret->_types=_types;
3248   if(!_coords)
3249     {
3250       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3251       ret->setCoords(coords);
3252     }
3253   else
3254     ret->setCoords(_coords);
3255   return ret.retn();
3256 }
3257
3258 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3259 {
3260   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3261   const mcIdType *pt=_nodal_connec->getConstPointer();
3262   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3263     return ptI[cellId+1]-ptI[cellId]-1;
3264   else
3265     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3266 }
3267
3268 /*!
3269  * Returns types of cells of the specified part of \a this mesh.
3270  * This method avoids computing sub-mesh explicitly to get its types.
3271  *  \param [in] begin - an array of cell ids of interest.
3272  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3273  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3274  *         describing the cell types.
3275  *  \throw If the coordinates array is not set.
3276  *  \throw If the nodal connectivity of cells is not defined.
3277  *  \sa getAllGeoTypes()
3278  */
3279 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3280 {
3281   checkFullyDefined();
3282   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3283   const mcIdType *conn=_nodal_connec->getConstPointer();
3284   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3285   for(const mcIdType *w=begin;w!=end;w++)
3286     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3287   return ret;
3288 }
3289
3290 /*!
3291  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3292  * Optionally updates
3293  * a set of types of cells constituting \a this mesh.
3294  * This method is for advanced users having prepared their connectivity before. For
3295  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3296  *  \param [in] conn - the nodal connectivity array.
3297  *  \param [in] connIndex - the nodal connectivity index array.
3298  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3299  *         mesh is updated.
3300  */
3301 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3302 {
3303   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3304   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3305   if(isComputingTypes)
3306     computeTypes();
3307   declareAsNew();
3308 }
3309
3310 /*!
3311  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3312  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3313  */
3314 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3315     _nodal_connec(0),_nodal_connec_index(0),
3316     _types(other._types)
3317 {
3318   if(other._nodal_connec)
3319     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3320   if(other._nodal_connec_index)
3321     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3322 }
3323
3324 MEDCouplingUMesh::~MEDCouplingUMesh()
3325 {
3326   if(_nodal_connec)
3327     _nodal_connec->decrRef();
3328   if(_nodal_connec_index)
3329     _nodal_connec_index->decrRef();
3330 }
3331
3332 /*!
3333  * Recomputes a set of cell types of \a this mesh. For more info see
3334  * \ref MEDCouplingUMeshNodalConnectivity.
3335  */
3336 void MEDCouplingUMesh::computeTypes()
3337 {
3338   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3339 }
3340
3341
3342 /*!
3343  * Returns a number of cells constituting \a this mesh.
3344  *  \return mcIdType - the number of cells in \a this mesh.
3345  *  \throw If the nodal connectivity of cells is not defined.
3346  */
3347 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3348 {
3349   if(_nodal_connec_index)
3350     return _nodal_connec_index->getNumberOfTuples()-1;
3351   else
3352     if(_mesh_dim==-1)
3353       return 1;
3354     else
3355       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3356 }
3357
3358 /*!
3359  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3360  * mesh. For more info see \ref meshes.
3361  *  \return int - the dimension of \a this mesh.
3362  *  \throw If the mesh dimension is not defined using setMeshDimension().
3363  */
3364 int MEDCouplingUMesh::getMeshDimension() const
3365 {
3366   if(_mesh_dim<-1)
3367     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3368   return _mesh_dim;
3369 }
3370
3371 /*!
3372  * Returns a length of the nodal connectivity array.
3373  * This method is for test reason. Normally the integer returned is not useable by
3374  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3375  *  \return mcIdType - the length of the nodal connectivity array.
3376  */
3377 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3378 {
3379   return _nodal_connec->getNbOfElems();
3380 }
3381
3382 /*!
3383  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3384  */
3385 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3386 {
3387   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3388   tinyInfo.push_back(ToIdType(getMeshDimension()));
3389   tinyInfo.push_back(getNumberOfCells());
3390   if(_nodal_connec)
3391     tinyInfo.push_back(getNodalConnectivityArrayLen());
3392   else
3393     tinyInfo.push_back(-1);
3394 }
3395
3396 /*!
3397  * First step of unserialization process.
3398  */
3399 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3400 {
3401   return tinyInfo[6]<=0;
3402 }
3403
3404 /*!
3405  * Second step of serialization process.
3406  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3407  * \param a1 DataArrayDouble
3408  * \param a2 DataArrayDouble
3409  * \param littleStrings string vector
3410  */
3411 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3412 {
3413   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3414   if(tinyInfo[5]!=-1)
3415     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3416 }
3417
3418 /*!
3419  * Third and final step of serialization process.
3420  */
3421 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3422 {
3423   MEDCouplingPointSet::serialize(a1,a2);
3424   if(getMeshDimension()>-1)
3425     {
3426       a1=DataArrayIdType::New();
3427       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3428       mcIdType *ptA1=a1->getPointer();
3429       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3430       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3431       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3432       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3433     }
3434   else
3435     a1=0;
3436 }
3437
3438 /*!
3439  * Second and final unserialization process.
3440  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3441  */
3442 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3443 {
3444   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3445   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3446   if(tinyInfo[7]!=-1)
3447     {
3448       // Connectivity
3449       const mcIdType *recvBuffer=a1->getConstPointer();
3450       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3451       myConnecIndex->alloc(tinyInfo[6]+1,1);
3452       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3453       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3454       myConnec->alloc(tinyInfo[7],1);
3455       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3456       setConnectivity(myConnec, myConnecIndex);
3457     }
3458 }
3459
3460
3461
3462 /*!
3463  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3464  * mesh.<br>
3465  * For 1D cells, the returned field contains lengths.<br>
3466  * For 2D cells, the returned field contains areas.<br>
3467  * For 3D cells, the returned field contains volumes.
3468  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3469  *         orientation, i.e. the volume is always positive.
3470  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3471  *         and one time . The caller is to delete this field using decrRef() as it is no
3472  *         more needed.
3473  */
3474 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3475 {
3476   std::string name="MeasureOfMesh_";
3477   name+=getName();
3478   mcIdType nbelem=getNumberOfCells();
3479   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3480   field->setName(name);
3481   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3482   array->alloc(nbelem,1);
3483   double *area_vol=array->getPointer();
3484   field->setArray(array) ; array=0;
3485   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3486   field->synchronizeTimeWithMesh();
3487   if(getMeshDimension()!=-1)
3488     {
3489       mcIdType ipt;
3490       INTERP_KERNEL::NormalizedCellType type;
3491       int dim_space=getSpaceDimension();
3492       const double *coords=getCoords()->getConstPointer();
3493       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3494       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3495       for(mcIdType iel=0;iel<nbelem;iel++)
3496         {
3497           ipt=connec_index[iel];
3498           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3499           area_vol[iel]=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space);
3500         }
3501       if(isAbs)
3502         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3503     }
3504   else
3505     {
3506       area_vol[0]=std::numeric_limits<double>::max();
3507     }
3508   return field.retn();
3509 }
3510
3511 /*!
3512  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3513  * mesh.<br>
3514  * For 1D cells, the returned array contains lengths.<br>
3515  * For 2D cells, the returned array contains areas.<br>
3516  * For 3D cells, the returned array contains volumes.
3517  * This method avoids building explicitly a part of \a this mesh to perform the work.
3518  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3519  *         orientation, i.e. the volume is always positive.
3520  *  \param [in] begin - an array of cell ids of interest.
3521  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3522  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3523  *          delete this array using decrRef() as it is no more needed.
3524  *
3525  *  \if ENABLE_EXAMPLES
3526  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3527  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3528  *  \endif
3529  *  \sa getMeasureField()
3530  */
3531 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3532 {
3533   std::string name="PartMeasureOfMesh_";
3534   name+=getName();
3535   std::size_t nbelem=std::distance(begin,end);
3536   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3537   array->setName(name);
3538   array->alloc(nbelem,1);
3539   double *area_vol=array->getPointer();
3540   if(getMeshDimension()!=-1)
3541     {
3542       mcIdType ipt;
3543       INTERP_KERNEL::NormalizedCellType type;
3544       int dim_space=getSpaceDimension();
3545       const double *coords=getCoords()->getConstPointer();
3546       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3547       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3548       for(const mcIdType *iel=begin;iel!=end;iel++)
3549         {
3550           ipt=connec_index[*iel];
3551           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3552           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3553         }
3554       if(isAbs)
3555         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3556     }
3557   else
3558     {
3559       area_vol[0]=std::numeric_limits<double>::max();
3560     }
3561   return array.retn();
3562 }
3563
3564 /*!
3565  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3566  * \a this one. The returned field contains the dual cell volume for each corresponding
3567  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3568  *  the dual mesh in P1 sens of \a this.<br>
3569  * For 1D cells, the returned field contains lengths.<br>
3570  * For 2D cells, the returned field contains areas.<br>
3571  * For 3D cells, the returned field contains volumes.
3572  * This method is useful to check "P1*" conservative interpolators.
3573  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3574  *         orientation, i.e. the volume is always positive.
3575  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3576  *          nodes and one time. The caller is to delete this array using decrRef() as
3577  *          it is no more needed.
3578  */
3579 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3580 {
3581   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3582   std::string name="MeasureOnNodeOfMesh_";
3583   name+=getName();
3584   mcIdType nbNodes=getNumberOfNodes();
3585   MCAuto<DataArrayDouble> nnpc;
3586   {
3587     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3588     nnpc=tmp2->convertToDblArr();
3589   }
3590   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3591   const double *nnpcPtr(nnpc->begin());
3592   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3593   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3594   array->alloc(nbNodes,1);
3595   double *valsToFill=array->getPointer();
3596   std::fill(valsToFill,valsToFill+nbNodes,0.);
3597   const double *values=tmp->getArray()->getConstPointer();
3598   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3599   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3600   getReverseNodalConnectivity(da,daInd);
3601   const mcIdType *daPtr=da->getConstPointer();
3602   const mcIdType *daIPtr=daInd->getConstPointer();
3603   for(mcIdType i=0;i<nbNodes;i++)
3604     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3605       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3606   ret->setMesh(this);
3607   ret->setArray(array);
3608   return ret.retn();
3609 }
3610
3611 /*!
3612  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3613  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3614  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3615  * and are normalized.
3616  * <br> \a this can be either
3617  * - a  2D mesh in 2D or 3D space or
3618  * - an 1D mesh in 2D space.
3619  *
3620  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3621  *          cells and one time. The caller is to delete this field using decrRef() as
3622  *          it is no more needed.
3623  *  \throw If the nodal connectivity of cells is not defined.
3624  *  \throw If the coordinates array is not set.
3625  *  \throw If the mesh dimension is not set.
3626  *  \throw If the mesh and space dimension is not as specified above.
3627  */
3628 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3629 {
3630   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3631     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3632   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3633   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3634   mcIdType nbOfCells=getNumberOfCells();
3635   int nbComp=getMeshDimension()+1;
3636   array->alloc(nbOfCells,nbComp);
3637   double *vals=array->getPointer();
3638   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3639   const mcIdType *conn=_nodal_connec->getConstPointer();
3640   const double *coords=_coords->getConstPointer();
3641   if(getMeshDimension()==2)
3642     {
3643       if(getSpaceDimension()==3)
3644         {
3645           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3646           const double *locPtr=loc->getConstPointer();
3647           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3648             {
3649               mcIdType offset=connI[i];
3650               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3651               double n=INTERP_KERNEL::norm<3>(vals);
3652               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3653             }
3654         }
3655       else
3656         {
3657           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3658           const double *isAbsPtr=isAbs->getArray()->begin();
3659           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3660             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3661         }
3662     }
3663   else//meshdimension==1
3664     {
3665       double tmp[2];
3666       for(mcIdType i=0;i<nbOfCells;i++)
3667         {
3668           mcIdType offset=connI[i];
3669           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3670           double n=INTERP_KERNEL::norm<2>(tmp);
3671           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3672           *vals++=-tmp[1];
3673           *vals++=tmp[0];
3674         }
3675     }
3676   ret->setArray(array);
3677   ret->setMesh(this);
3678   ret->synchronizeTimeWithSupport();
3679   return ret.retn();
3680 }
3681
3682 /*!
3683  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3684  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3685  * and are normalized.
3686  * <br> \a this can be either
3687  * - a  2D mesh in 2D or 3D space or
3688  * - an 1D mesh in 2D space.
3689  *
3690  * This method avoids building explicitly a part of \a this mesh to perform the work.
3691  *  \param [in] begin - an array of cell ids of interest.
3692  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3693  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3694  *          cells and one time. The caller is to delete this field using decrRef() as
3695  *          it is no more needed.
3696  *  \throw If the nodal connectivity of cells is not defined.
3697  *  \throw If the coordinates array is not set.
3698  *  \throw If the mesh dimension is not set.
3699  *  \throw If the mesh and space dimension is not as specified above.
3700  *  \sa buildOrthogonalField()
3701  *
3702  *  \if ENABLE_EXAMPLES
3703  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3704  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3705  *  \endif
3706  */
3707 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3708 {
3709   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3710     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3711   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3712   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3713   std::size_t nbelems=std::distance(begin,end);
3714   int nbComp=getMeshDimension()+1;
3715   array->alloc(nbelems,nbComp);
3716   double *vals=array->getPointer();
3717   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3718   const mcIdType *conn=_nodal_connec->getConstPointer();
3719   const double *coords=_coords->getConstPointer();
3720   if(getMeshDimension()==2)
3721     {
3722       if(getSpaceDimension()==3)
3723         {
3724           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3725           const double *locPtr=loc->getConstPointer();
3726           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3727             {
3728               mcIdType offset=connI[*i];
3729               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3730               double n=INTERP_KERNEL::norm<3>(vals);
3731               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3732             }
3733         }
3734       else
3735         {
3736           for(std::size_t i=0;i<nbelems;i++)
3737             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3738         }
3739     }
3740   else//meshdimension==1
3741     {
3742       double tmp[2];
3743       for(const mcIdType *i=begin;i!=end;i++)
3744         {
3745           mcIdType offset=connI[*i];
3746           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3747           double n=INTERP_KERNEL::norm<2>(tmp);
3748           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3749           *vals++=-tmp[1];
3750           *vals++=tmp[0];
3751         }
3752     }
3753   ret->setArray(array);
3754   ret->setMesh(this);
3755   ret->synchronizeTimeWithSupport();
3756   return ret.retn();
3757 }
3758
3759 /*!
3760  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3761  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3762  * and are \b not normalized.
3763  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3764  *          cells and one time. The caller is to delete this field using decrRef() as
3765  *          it is no more needed.
3766  *  \throw If the nodal connectivity of cells is not defined.
3767  *  \throw If the coordinates array is not set.
3768  *  \throw If \a this->getMeshDimension() != 1.
3769  *  \throw If \a this mesh includes cells of type other than SEG2.
3770  */
3771 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3772 {
3773   if(getMeshDimension()!=1)
3774     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3775   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3776     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3777   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3778   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3779   mcIdType nbOfCells=getNumberOfCells();
3780   int spaceDim=getSpaceDimension();
3781   array->alloc(nbOfCells,spaceDim);
3782   double *pt=array->getPointer();
3783   const double *coo=getCoords()->getConstPointer();
3784   std::vector<mcIdType> conn;
3785   conn.reserve(2);
3786   for(mcIdType i=0;i<nbOfCells;i++)
3787     {
3788       conn.resize(0);
3789       getNodeIdsOfCell(i,conn);
3790       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3791     }
3792   ret->setArray(array);
3793   ret->setMesh(this);
3794   ret->synchronizeTimeWithSupport();
3795   return ret.retn();
3796 }
3797
3798 /*!
3799  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3800  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3801  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3802  * from. If a result face is shared by two 3D cells, then the face in included twice in
3803  * the result mesh.
3804  *  \param [in] origin - 3 components of a point defining location of the plane.
3805  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3806  *         must be greater than 1e-6.
3807  *  \param [in] eps - half-thickness of the plane.
3808  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3809  *         producing correspondent 2D cells. The caller is to delete this array
3810  *         using decrRef() as it is no more needed.
3811  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3812  *         not share the node coordinates array with \a this mesh. The caller is to
3813  *         delete this mesh using decrRef() as it is no more needed.
3814  *  \throw If the coordinates array is not set.
3815  *  \throw If the nodal connectivity of cells is not defined.
3816  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3817  *  \throw If magnitude of \a vec is less than 1e-6.
3818  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3819  *  \throw If \a this includes quadratic cells.
3820  */
3821 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3822 {
3823   checkFullyDefined();
3824   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3825     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3826   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3827   if(candidates->empty())
3828     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3829   std::vector<mcIdType> nodes;
3830   DataArrayIdType *cellIds1D=0;
3831   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3832   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3833   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3834   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3835   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3836   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3837   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3838   revDesc2=0; revDescIndx2=0;
3839   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3840   revDesc1=0; revDescIndx1=0;
3841   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3842   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3843   //
3844   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3845   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3846     cut3DCurve[*it]=-1;
3847   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3848   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3849   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3850                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3851                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3852   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3853   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3854   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3855   if(cellIds2->empty())
3856     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3857   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3858   ret->setCoords(mDesc1->getCoords());
3859   ret->setConnectivity(conn,connI,true);
3860   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3861   return ret.retn();
3862 }
3863
3864 /*!
3865  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3866 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
3867 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3868 the result mesh.
3869  *  \param [in] origin - 3 components of a point defining location of the plane.
3870  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3871  *         must be greater than 1e-6.
3872  *  \param [in] eps - half-thickness of the plane.
3873  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3874  *         producing correspondent segments. The caller is to delete this array
3875  *         using decrRef() as it is no more needed.
3876  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3877  *         mesh in 3D space. This mesh does not share the node coordinates array with
3878  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3879  *         no more needed.
3880  *  \throw If the coordinates array is not set.
3881  *  \throw If the nodal connectivity of cells is not defined.
3882  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3883  *  \throw If magnitude of \a vec is less than 1e-6.
3884  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3885  *  \throw If \a this includes quadratic cells.
3886  */
3887 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3888 {
3889   checkFullyDefined();
3890   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3891     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3892   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3893   if(candidates->empty())
3894     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3895   std::vector<mcIdType> nodes;
3896   DataArrayIdType *cellIds1D(0);
3897   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3898   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3899   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3900   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3901   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3902   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3903   //
3904   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3905   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3906     cut3DCurve[*it]=-1;
3907   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3908   mcIdType ncellsSub=subMesh->getNumberOfCells();
3909   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3910   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3911                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3912                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3913   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3914   conn->alloc(0,1);
3915   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3916   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3917   for(mcIdType i=0;i<ncellsSub;i++)
3918     {
3919       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3920         {
3921           if(cut3DSurf[i].first!=-2)
3922             {
3923               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3924               connI->pushBackSilent(conn->getNumberOfTuples());
3925               cellIds2->pushBackSilent(i);
3926             }
3927           else
3928             {
3929               mcIdType cellId3DSurf=cut3DSurf[i].second;
3930               mcIdType offset=nodalI[cellId3DSurf]+1;
3931               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3932               for(mcIdType j=0;j<nbOfEdges;j++)
3933                 {
3934                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3935                   connI->pushBackSilent(conn->getNumberOfTuples());
3936                   cellIds2->pushBackSilent(cellId3DSurf);
3937                 }
3938             }
3939         }
3940     }
3941   if(cellIds2->empty())
3942     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3943   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3944   ret->setCoords(mDesc1->getCoords());
3945   ret->setConnectivity(conn,connI,true);
3946   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3947   return ret.retn();
3948 }
3949
3950 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3951 {
3952   checkFullyDefined();
3953   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3954     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3955   if(getNumberOfCells()!=1)
3956     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3957   //
3958   std::vector<mcIdType> nodes;
3959   findNodesOnPlane(origin,vec,eps,nodes);
3960   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());
3961   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3962   revDesc2=0; revDescIndx2=0;
3963   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3964   revDesc1=0; revDescIndx1=0;
3965   DataArrayIdType *cellIds1D(0);
3966   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3967   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3968   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3969   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3970     cut3DCurve[*it]=-1;
3971   bool sameNbNodes;
3972   {
3973     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3974     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3975     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3976   }
3977   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3978   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3979                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3980                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3981   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3982   connI->pushBackSilent(0); conn->alloc(0,1);
3983   {
3984     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3985     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3986     if(cellIds2->empty())
3987       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3988   }
3989   std::vector<std::vector<mcIdType> > res;
3990   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3991   std::size_t sz(res.size());
3992   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3993     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3994   for(std::size_t i=0;i<sz;i++)
3995     {
3996       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3997       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3998       connI->pushBackSilent(conn->getNumberOfTuples());
3999     }
4000   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
4001   ret->setCoords(mDesc1->getCoords());
4002   ret->setConnectivity(conn,connI,true);
4003   mcIdType nbCellsRet(ret->getNumberOfCells());
4004   //
4005   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
4006   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
4007   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
4008   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
4009   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
4010   MCAuto<DataArrayDouble> occm;
4011   {
4012     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
4013     occm=DataArrayDouble::Substract(ccm,pt);
4014   }
4015   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
4016   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);
4017   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
4018   //
4019   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
4020   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
4021   ret2->setCoords(mDesc1->getCoords());
4022   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
4023   conn2I->pushBackSilent(0); conn2->alloc(0,1);
4024   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4025   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
4026   if(dott->getIJ(0,0)>0)
4027     {
4028       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
4029       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
4030     }
4031   else
4032     {
4033       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
4034       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
4035     }
4036   for(mcIdType i=1;i<nbCellsRet;i++)
4037     {
4038       if(dott2->getIJ(i,0)<0)
4039         {
4040           if(ciPtr[i+1]-ciPtr[i]>=4)
4041             {
4042               cell0.push_back(-1);
4043               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4044             }
4045         }
4046       else
4047         {
4048           if(ciPtr[i+1]-ciPtr[i]>=4)
4049             {
4050               cell1.push_back(-1);
4051               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
4052             }
4053         }
4054     }
4055   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
4056   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4057   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
4058   conn2I->pushBackSilent(conn2->getNumberOfTuples());
4059   ret2->setConnectivity(conn2,conn2I,true);
4060   ret2->checkConsistencyLight();
4061   ret2->orientCorrectlyPolyhedrons();
4062   return ret2;
4063 }
4064
4065 /*!
4066  * Finds cells whose bounding boxes intersect a given plane.
4067  *  \param [in] origin - 3 components of a point defining location of the plane.
4068  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
4069  *         must be greater than 1e-6.
4070  *  \param [in] eps - half-thickness of the plane.
4071  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
4072  *         cells. The caller is to delete this array using decrRef() as it is no more
4073  *         needed.
4074  *  \throw If the coordinates array is not set.
4075  *  \throw If the nodal connectivity of cells is not defined.
4076  *  \throw If \a this->getSpaceDimension() != 3.
4077  *  \throw If magnitude of \a vec is less than 1e-6.
4078  *  \sa buildSlice3D()
4079  */
4080 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
4081 {
4082   checkFullyDefined();
4083   if(getSpaceDimension()!=3)
4084     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
4085   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4086   if(normm<1e-6)
4087     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4088   double vec2[3];
4089   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
4090   double angle=acos(vec[2]/normm);
4091   MCAuto<DataArrayIdType> cellIds;
4092   double bbox[6];
4093   if(angle>eps)
4094     {
4095       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
4096       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
4097       if(normm2/normm>1e-6)
4098         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4099       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4100       mw->setCoords(coo);
4101       mw->getBoundingBox(bbox);
4102       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4103       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4104     }
4105   else
4106     {
4107       getBoundingBox(bbox);
4108       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4109       cellIds=getCellsInBoundingBox(bbox,eps);
4110     }
4111   return cellIds.retn();
4112 }
4113
4114 /*!
4115  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4116  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4117  * No consideration of coordinate is done by this method.
4118  * 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)
4119  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4120  */
4121 bool MEDCouplingUMesh::isContiguous1D() const
4122 {
4123   if(getMeshDimension()!=1)
4124     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4125   mcIdType nbCells=getNumberOfCells();
4126   if(nbCells<1)
4127     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4128   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4129   mcIdType ref=conn[connI[0]+2];
4130   for(mcIdType i=1;i<nbCells;i++)
4131     {
4132       if(conn[connI[i]+1]!=ref)
4133         return false;
4134       ref=conn[connI[i]+2];
4135     }
4136   return true;
4137 }
4138
4139 /*!
4140  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4141  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4142  * \param pt reference point of the line
4143  * \param v normalized director vector of the line
4144  * \param eps max precision before throwing an exception
4145  * \param res output of size this->getNumberOfCells
4146  */
4147 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4148 {
4149   if(getMeshDimension()!=1)
4150     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4151   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4152     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4153   if(getSpaceDimension()!=3)
4154     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4155   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4156   const double *fPtr=f->getArray()->getConstPointer();
4157   double tmp[3];
4158   for(mcIdType i=0;i<getNumberOfCells();i++)
4159     {
4160       const double *tmp1=fPtr+3*i;
4161       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4162       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4163       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4164       double n1=INTERP_KERNEL::norm<3>(tmp);
4165       n1/=INTERP_KERNEL::norm<3>(tmp1);
4166       if(n1>eps)
4167         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4168     }
4169   const double *coo=getCoords()->getConstPointer();
4170   for(mcIdType i=0;i<getNumberOfNodes();i++)
4171     {
4172       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4173       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4174       res[i]=std::accumulate(tmp,tmp+3,0.);
4175     }
4176 }
4177
4178 /*!
4179  * 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.
4180  * \a this is expected to be a mesh so that its space dimension is equal to its
4181  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4182  * 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).
4183  *
4184  * 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
4185  * 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).
4186  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4187  *
4188  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4189  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4190  *
4191  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4192  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4193  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4194  * \return the positive value of the distance.
4195  * \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
4196  * dimension - 1.
4197  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4198  */
4199 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4200 {
4201   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4202   if(meshDim!=spaceDim-1)
4203     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4204   if(meshDim!=2 && meshDim!=1)
4205     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4206   checkFullyDefined();
4207   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4208     { 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()); }
4209   DataArrayIdType *ret1=0;
4210   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4211   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4212   MCAuto<DataArrayIdType> ret1Safe(ret1);
4213   cellId=*ret1Safe->begin();
4214   return *ret0->begin();
4215 }
4216
4217 /*!
4218  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4219  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4220  * 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
4221  * 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).
4222  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4223  *
4224  * \a this is expected to be a mesh so that its space dimension is equal to its
4225  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4226  * 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).
4227  *
4228  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4229  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4230  *
4231  * \param [in] pts the list of points in which each tuple represents a point
4232  * \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.
4233  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4234  * \throw if number of components of \a pts is not equal to the space dimension.
4235  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4236  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4237  */
4238 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4239 {
4240   if(!pts)
4241     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4242   pts->checkAllocated();
4243   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4244   if(meshDim!=spaceDim-1)
4245     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4246   if(meshDim!=2 && meshDim!=1)
4247     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4248   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4249     {
4250       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4251       throw INTERP_KERNEL::Exception(oss.str());
4252     }
4253   checkFullyDefined();
4254   mcIdType nbCells=getNumberOfCells();
4255   if(nbCells==0)
4256     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4257   mcIdType nbOfPts=pts->getNumberOfTuples();
4258   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4259   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4260   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4261   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4262   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4263   const double *bbox(bboxArr->begin());
4264   switch(spaceDim)
4265   {
4266     case 3:
4267       {
4268         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4269         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4270           {
4271             double x=std::numeric_limits<double>::max();
4272             std::vector<mcIdType> elems;
4273             myTree.getMinDistanceOfMax(ptsPtr,x);
4274             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4275             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4276           }
4277         break;
4278       }
4279     case 2:
4280       {
4281         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4282         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4283           {
4284             double x=std::numeric_limits<double>::max();
4285             std::vector<mcIdType> elems;
4286             myTree.getMinDistanceOfMax(ptsPtr,x);
4287             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4288             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4289           }
4290         break;
4291       }
4292     default:
4293       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4294   }
4295   cellIds=ret1.retn();
4296   return ret0.retn();
4297 }
4298
4299 /// @cond INTERNAL
4300
4301 /// @endcond
4302
4303 /*!
4304  * Finds cells in contact with a ball (i.e. a point with precision).
4305  * 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.
4306  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4307  *
4308  * \warning This method is suitable if the caller intends to evaluate only one
4309  *          point, for more points getCellsContainingPoints() is recommended as it is
4310  *          faster.
4311  *  \param [in] pos - array of coordinates of the ball central point.
4312  *  \param [in] eps - ball radius.
4313  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4314  *         if there are no such cells.
4315  *  \throw If the coordinates array is not set.
4316  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4317  */
4318 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4319 {
4320   std::vector<mcIdType> elts;
4321   getCellsContainingPoint(pos,eps,elts);
4322   if(elts.empty())
4323     return -1;
4324   return elts.front();
4325 }
4326
4327 /*!
4328  * Finds cells in contact with a ball (i.e. a point with precision).
4329  * For speed reasons, the INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6 and INTERP_KERNEL::NORM_QUAD8 cells are considered as convex cells to detect if a point is IN or OUT.
4330  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4331  * \warning This method is suitable if the caller intends to evaluate only one
4332  *          point, for more points getCellsContainingPoints() is recommended as it is
4333  *          faster.
4334  *  \param [in] pos - array of coordinates of the ball central point.
4335  *  \param [in] eps - ball radius.
4336  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4337  *         before inserting ids.
4338  *  \throw If the coordinates array is not set.
4339  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4340  *
4341  *  \if ENABLE_EXAMPLES
4342  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4343  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4344  *  \endif
4345  */
4346 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4347 {
4348   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4349   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4350   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4351 }
4352
4353 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4354                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4355                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4356 {
4357   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4358   if(spaceDim==3)
4359     {
4360       if(mDim==3)
4361         {
4362           const double *coords=_coords->getConstPointer();
4363           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4364         }
4365       else
4366         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4367     }
4368   else if(spaceDim==2)
4369     {
4370       if(mDim==2)
4371         {
4372           const double *coords=_coords->getConstPointer();
4373           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4374         }
4375       else
4376         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4377     }
4378   else if(spaceDim==1)
4379     {
4380       if(mDim==1)
4381         {
4382           const double *coords=_coords->getConstPointer();
4383           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4384         }
4385       else
4386         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4387     }
4388   else
4389     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4390 }
4391
4392 /*!
4393  * Finds cells in contact with several balls (i.e. points with precision).
4394  * This method is an extension of getCellContainingPoint() and
4395  * getCellsContainingPoint() for the case of multiple points.
4396  * 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.
4397  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4398  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4399  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4400  *         this->getSpaceDimension() * \a nbOfPoints
4401  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4402  *  \param [in] eps - radius of balls (i.e. the precision).
4403  *  \param [out] elts - vector returning ids of found cells.
4404  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4405  *         dividing cell ids in \a elts into groups each referring to one
4406  *         point. Its every element (except the last one) is an index pointing to the
4407  *         first id of a group of cells. For example cells in contact with the *i*-th
4408  *         point are described by following range of indices:
4409  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4410  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4411  *         Number of cells in contact with the *i*-th point is
4412  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4413  *  \throw If the coordinates array is not set.
4414  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4415  *
4416  *  \if ENABLE_EXAMPLES
4417  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4418  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4419  *  \endif
4420  */
4421 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4422                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4423 {
4424   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4425   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4426 }
4427
4428 /*!
4429  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4430  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4431  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4432  * 
4433  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4434  */
4435 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4436 {
4437   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4438   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4439 }
4440
4441 /*!
4442  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4443  * least two its edges intersect each other anywhere except their extremities. An
4444  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4445  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4446  *         cleared before filling in.
4447  *  \param [in] eps - precision.
4448  *  \throw If \a this->getMeshDimension() != 2.
4449  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4450  */
4451 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4452 {
4453   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4454   if(getMeshDimension()!=2)
4455     throw INTERP_KERNEL::Exception(msg);
4456   int spaceDim=getSpaceDimension();
4457   if(spaceDim!=2 && spaceDim!=3)
4458     throw INTERP_KERNEL::Exception(msg);
4459   const mcIdType *conn=_nodal_connec->getConstPointer();
4460   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4461   mcIdType nbOfCells=getNumberOfCells();
4462   std::vector<double> cell2DinS2;
4463   for(mcIdType i=0;i<nbOfCells;i++)
4464     {
4465       mcIdType offset=connI[i];
4466       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4467       if(nbOfNodesForCell<=3)
4468         continue;
4469       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4470       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4471       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4472         cells.push_back(i);
4473       cell2DinS2.clear();
4474     }
4475 }
4476
4477 /*!
4478  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4479  *
4480  * 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.
4481  * 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.
4482  *
4483  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4484  * This convex envelop is computed using Jarvis march algorithm.
4485  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4486  * 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)
4487  * 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.
4488  *
4489  * \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.
4490  * \sa MEDCouplingUMesh::colinearize2D
4491  */
4492 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4493 {
4494   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4495     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4496   checkFullyDefined();
4497   const double *coords=getCoords()->getConstPointer();
4498   mcIdType nbOfCells=getNumberOfCells();
4499   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4500   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4501   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4502   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4503   *workIndexOut=0;
4504   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4505   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4506   std::set<INTERP_KERNEL::NormalizedCellType> types;
4507   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4508   isChanged->alloc(0,1);
4509   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4510     {
4511       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4512       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4513         isChanged->pushBackSilent(i);
4514       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4515       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4516     }
4517   if(isChanged->empty())
4518     return 0;
4519   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4520   _types=types;
4521   return isChanged.retn();
4522 }
4523
4524 /*!
4525  * This method is \b NOT const because it can modify \a this.
4526  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4527  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4528  * \param policy specifies the type of extrusion chosen:
4529  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4530  *   will be repeated to build each level
4531  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4532  *   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
4533  *   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
4534  *   arc.
4535  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4536  */
4537 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4538 {
4539   checkFullyDefined();
4540   mesh1D->checkFullyDefined();
4541   if(!mesh1D->isContiguous1D())
4542     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4543   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4544     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4545   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4546     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4547   if(mesh1D->getMeshDimension()!=1)
4548     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4549   bool isQuad=false;
4550   if(isPresenceOfQuadratic())
4551     {
4552       if(mesh1D->isFullyQuadratic())
4553         isQuad=true;
4554       else
4555         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4556     }
4557   mcIdType oldNbOfNodes(getNumberOfNodes());
4558   MCAuto<DataArrayDouble> newCoords;
4559   switch(policy)
4560   {
4561     case 0:
4562       {
4563         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4564         break;
4565       }
4566     case 1:
4567       {
4568         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4569         break;
4570       }
4571     default:
4572       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4573   }
4574   setCoords(newCoords);
4575   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4576   updateTime();
4577   return ret.retn();
4578 }
4579
4580
4581 /*!
4582  * Checks if \a this mesh is constituted by only quadratic cells.
4583  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4584  *  \throw If the coordinates array is not set.
4585  *  \throw If the nodal connectivity of cells is not defined.
4586  */
4587 bool MEDCouplingUMesh::isFullyQuadratic() const
4588 {
4589   checkFullyDefined();
4590   bool ret=true;
4591   mcIdType nbOfCells=getNumberOfCells();
4592   for(mcIdType i=0;i<nbOfCells && ret;i++)
4593     {
4594       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4595       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4596       ret=cm.isQuadratic();
4597     }
4598   return ret;
4599 }
4600
4601 /*!
4602  * Checks if \a this mesh includes any quadratic cell.
4603  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4604  *  \throw If the coordinates array is not set.
4605  *  \throw If the nodal connectivity of cells is not defined.
4606  */
4607 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4608 {
4609   checkFullyDefined();
4610   bool ret=false;
4611   mcIdType nbOfCells=getNumberOfCells();
4612   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4613     {
4614       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4615       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4616       ret=cm.isQuadratic();
4617     }
4618   return ret;
4619 }
4620
4621 /*!
4622  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4623  * this mesh, it remains unchanged.
4624  *  \throw If the coordinates array is not set.
4625  *  \throw If the nodal connectivity of cells is not defined.
4626  */
4627 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4628 {
4629   checkFullyDefined();
4630   mcIdType nbOfCells=getNumberOfCells();
4631   mcIdType delta=0;
4632   const mcIdType *iciptr=_nodal_connec_index->begin();
4633   for(mcIdType i=0;i<nbOfCells;i++)
4634     {
4635       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4636       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4637       if(cm.isQuadratic())
4638         {
4639           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4640           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4641           if(!cml.isDynamic())
4642             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4643           else
4644             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4645         }
4646     }
4647   if(delta==0)
4648     return ;
4649   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4650   const mcIdType *icptr(_nodal_connec->begin());
4651   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4652   newConnI->alloc(nbOfCells+1,1);
4653   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4654   *ociptr=0;
4655   _types.clear();
4656   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4657     {
4658       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4659       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4660       if(!cm.isQuadratic())
4661         {
4662           _types.insert(type);
4663           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4664           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4665         }
4666       else
4667         {
4668           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4669           _types.insert(typel);
4670           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4671           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4672           if(cml.isDynamic())
4673             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4674           *ocptr++=ToIdType(typel);
4675           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4676           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4677         }
4678     }
4679   setConnectivity(newConn,newConnI,false);
4680 }
4681
4682 /*!
4683  * This method converts all linear cell in \a this to quadratic one.
4684  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4685  * 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)
4686  * 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.
4687  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4688  * end of the existing coordinates.
4689  *
4690  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4691  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4692  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4693  *
4694  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4695  *
4696  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4697  */
4698 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4699 {
4700   DataArrayIdType *conn=0,*connI=0;
4701   DataArrayDouble *coords=0;
4702   std::set<INTERP_KERNEL::NormalizedCellType> types;
4703   checkFullyDefined();
4704   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4705   MCAuto<DataArrayDouble> coordsSafe;
4706   int meshDim=getMeshDimension();
4707   switch(conversionType)
4708   {
4709     case 0:
4710       switch(meshDim)
4711       {
4712         case 1:
4713           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4714           connSafe=conn; connISafe=connI; coordsSafe=coords;
4715           break;
4716         case 2:
4717           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4718           connSafe=conn; connISafe=connI; coordsSafe=coords;
4719           break;
4720         case 3:
4721           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4722           connSafe=conn; connISafe=connI; coordsSafe=coords;
4723           break;
4724         default:
4725           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4726       }
4727       break;
4728         case 1:
4729           {
4730             switch(meshDim)
4731             {
4732               case 1:
4733                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4734                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4735                 break;
4736               case 2:
4737                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4738                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4739                 break;
4740               case 3:
4741                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4742                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4743                 break;
4744               default:
4745                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4746             }
4747             break;
4748           }
4749         default:
4750           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4751   }
4752   setConnectivity(connSafe,connISafe,false);
4753   _types=types;
4754   setCoords(coordsSafe);
4755   return ret.retn();
4756 }
4757
4758 /*!
4759  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4760  * so that the number of cells remains the same. Quadratic faces are converted to
4761  * polygons. This method works only for 2D meshes in
4762  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4763  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4764  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4765  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4766  *         a polylinized edge constituting the input polygon.
4767  *  \throw If the coordinates array is not set.
4768  *  \throw If the nodal connectivity of cells is not defined.
4769  *  \throw If \a this->getMeshDimension() != 2.
4770  *  \throw If \a this->getSpaceDimension() != 2.
4771  */
4772 void MEDCouplingUMesh::tessellate2D(double eps)
4773 {
4774   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4775   if(spaceDim!=2)
4776     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4777   switch(meshDim)
4778     {
4779     case 1:
4780       return tessellate2DCurveInternal(eps);
4781     case 2:
4782       return tessellate2DInternal(eps);
4783     default:
4784       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4785     }
4786 }
4787
4788 #if 0
4789 /*!
4790  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4791  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4792  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4793  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4794  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4795  * This method can be seen as the opposite method of colinearize2D.
4796  * 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
4797  * to avoid to modify the numbering of existing nodes.
4798  *
4799  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4800  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4801  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4802  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4803  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4804  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4805  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4806  *
4807  * \sa buildDescendingConnectivity2
4808  */
4809 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4810                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4811 {
4812   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4813     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4814   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4815   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4816     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4817   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4818     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4819   //DataArrayIdType *out0(0),*outi0(0);
4820   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4821   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4822   //out0s=out0s->buildUnique(); out0s->sort(true);
4823 }
4824 #endif
4825
4826
4827 /*!
4828  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4829  * In addition, returns an array mapping new cells to old ones. <br>
4830  * This method typically increases the number of cells in \a this mesh
4831  * but the number of nodes remains \b unchanged.
4832  * That's why the 3D splitting policies
4833  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4834  *  \param [in] policy - specifies a pattern used for splitting.
4835  * The semantic of \a policy is:
4836  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4837  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4838  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4839  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4840  *
4841  *
4842  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4843  *          an id of old cell producing it. The caller is to delete this array using
4844  *         decrRef() as it is no more needed.
4845  *
4846  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4847  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4848  *          and \a this->getMeshDimension() != 3.
4849  *  \throw If \a policy is not one of the four discussed above.
4850  *  \throw If the nodal connectivity of cells is not defined.
4851  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4852  */
4853 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4854 {
4855   switch(policy)
4856   {
4857     case 0:
4858       return simplexizePol0();
4859     case 1:
4860       return simplexizePol1();
4861     case INTERP_KERNEL::PLANAR_FACE_5:
4862         return simplexizePlanarFace5();
4863     case INTERP_KERNEL::PLANAR_FACE_6:
4864         return simplexizePlanarFace6();
4865     default:
4866       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)");
4867   }
4868 }
4869
4870 /*!
4871  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4872  * - 1D: INTERP_KERNEL::NORM_SEG2
4873  * - 2D: INTERP_KERNEL::NORM_TRI3
4874  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4875  *
4876  * This method is useful for users that need to use P1 field services as
4877  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4878  * All these methods need mesh support containing only simplex cells.
4879  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4880  *  \throw If the coordinates array is not set.
4881  *  \throw If the nodal connectivity of cells is not defined.
4882  *  \throw If \a this->getMeshDimension() < 1.
4883  */
4884 bool MEDCouplingUMesh::areOnlySimplexCells() const
4885 {
4886   checkFullyDefined();
4887   int mdim=getMeshDimension();
4888   if(mdim<1 || mdim>3)
4889     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4890   mcIdType nbCells=getNumberOfCells();
4891   const mcIdType *conn=_nodal_connec->begin();
4892   const mcIdType *connI=_nodal_connec_index->begin();
4893   for(mcIdType i=0;i<nbCells;i++)
4894     {
4895       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4896       if(!cm.isSimplex())
4897         return false;
4898     }
4899   return true;
4900 }
4901
4902
4903
4904 /*!
4905  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4906  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4907  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4908  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4909  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4910  * so it can be useful to call mergeNodes() before calling this method.
4911  *  \throw If \a this->getMeshDimension() <= 1.
4912  *  \throw If the coordinates array is not set.
4913  *  \throw If the nodal connectivity of cells is not defined.
4914  */
4915 void MEDCouplingUMesh::convertDegeneratedCells()
4916 {
4917   checkFullyDefined();
4918   if(getMeshDimension()<=1)
4919     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4920   mcIdType nbOfCells=getNumberOfCells();
4921   if(nbOfCells<1)
4922     return ;
4923   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4924   mcIdType *conn=_nodal_connec->getPointer();
4925   mcIdType *index=_nodal_connec_index->getPointer();
4926   mcIdType posOfCurCell=0;
4927   mcIdType newPos=0;
4928   mcIdType lgthOfCurCell;
4929   for(mcIdType i=0;i<nbOfCells;i++)
4930     {
4931       lgthOfCurCell=index[i+1]-posOfCurCell;
4932       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4933       mcIdType newLgth;
4934       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4935                                                                                                      conn+newPos+1,newLgth);
4936       conn[newPos]=newType;
4937       newPos+=newLgth+1;
4938       posOfCurCell=index[i+1];
4939       index[i+1]=newPos;
4940     }
4941   if(newPos!=initMeshLgth)
4942     _nodal_connec->reAlloc(newPos);
4943   computeTypes();
4944 }
4945
4946 /*!
4947  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4948  * A cell is flat in the following cases:
4949  *   - for a linear cell, all points in the connectivity are equal
4950  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4951  *   identical quadratic points
4952  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4953  *      this array using decrRef() as it is no more needed.
4954  */
4955 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4956 {
4957   checkFullyDefined();
4958   if(getMeshDimension()<=1)
4959     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4960   mcIdType nbOfCells=getNumberOfCells();
4961   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4962   if(nbOfCells<1)
4963     return ret.retn();
4964   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4965   mcIdType *conn=_nodal_connec->getPointer();
4966   mcIdType *index=_nodal_connec_index->getPointer();
4967   mcIdType posOfCurCell=0;
4968   mcIdType newPos=0;
4969   mcIdType lgthOfCurCell, nbDelCells(0);
4970   for(mcIdType i=0;i<nbOfCells;i++)
4971     {
4972       lgthOfCurCell=index[i+1]-posOfCurCell;
4973       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4974       mcIdType newLgth;
4975       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4976                                                                                                      conn+newPos+1,newLgth);
4977       // Shall we delete the cell if it is completely degenerated:
4978       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4979       if (delCell)
4980         {
4981           nbDelCells++;
4982           ret->pushBackSilent(i);
4983         }
4984       else   //if the cell is to be deleted, simply stay at the same place
4985         {
4986           conn[newPos]=newType;
4987           newPos+=newLgth+1;
4988         }
4989       posOfCurCell=index[i+1];
4990       index[i+1-nbDelCells]=newPos;
4991     }
4992   if(newPos!=initMeshLgth)
4993     _nodal_connec->reAlloc(newPos);
4994   const mcIdType nCellDel=ret->getNumberOfTuples();
4995   if (nCellDel)
4996     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4997   computeTypes();
4998   return ret.retn();
4999 }
5000
5001 /*!
5002  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
5003  * Only connectivity is considered here.
5004  */
5005 bool MEDCouplingUMesh::removeDegenerated1DCells()
5006 {
5007   checkConnectivityFullyDefined();
5008   if(getMeshDimension()!=1)
5009     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
5010   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
5011   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
5012   {
5013     for(std::size_t i=0;i<nbCells;i++)
5014       {
5015         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
5016         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
5017           {
5018             if(conn[conni[i]+1]!=conn[conni[i]+2])
5019               {
5020                 newSize++;
5021                 newSize2+=conni[i+1]-conni[i];
5022               }
5023           }
5024         else
5025           {
5026             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
5027             throw INTERP_KERNEL::Exception(oss.str());
5028           }
5029       }
5030   }
5031   if(newSize==nbCells)//no cells has been removed -> do nothing
5032     return false;
5033   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
5034   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
5035   for(std::size_t i=0;i<nbCells;i++)
5036     {
5037       if(conn[conni[i]+1]!=conn[conni[i]+2])
5038         {
5039           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
5040           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
5041           newConnIPtr++;
5042         }
5043     }
5044   setConnectivity(newConn,newConnI,true);
5045   return true;
5046 }
5047
5048 /*!
5049  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
5050  * A cell is considered to be oriented correctly if an angle between its
5051  * normal vector and a given vector is less than \c PI / \c 2.
5052  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5053  *         cells.
5054  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5055  *         checked.
5056  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5057  *         is not cleared before filling in.
5058  *  \throw If \a this->getMeshDimension() != 2.
5059  *  \throw If \a this->getSpaceDimension() != 3.
5060  *
5061  *  \if ENABLE_EXAMPLES
5062  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5063  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5064  *  \endif
5065  */
5066 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
5067 {
5068   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5069     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
5070   mcIdType nbOfCells=getNumberOfCells();
5071   const mcIdType *conn=_nodal_connec->begin();
5072   const mcIdType *connI=_nodal_connec_index->begin();
5073   const double *coordsPtr=_coords->begin();
5074   for(mcIdType i=0;i<nbOfCells;i++)
5075     {
5076       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5077       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5078         {
5079           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
5080           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5081             cells.push_back(i);
5082         }
5083     }
5084 }
5085
5086 /*!
5087  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
5088  * considered to be oriented correctly if an angle between its normal vector and a
5089  * given vector is less than \c PI / \c 2.
5090  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
5091  *         cells.
5092  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
5093  *         checked.
5094  *  \throw If \a this->getMeshDimension() != 2.
5095  *  \throw If \a this->getSpaceDimension() != 3.
5096  *
5097  *  \if ENABLE_EXAMPLES
5098  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5099  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5100  *  \endif
5101  *
5102  *  \sa changeOrientationOfCells
5103  */
5104 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5105 {
5106   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5107     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5108   mcIdType nbOfCells=getNumberOfCells();
5109   mcIdType *conn(_nodal_connec->getPointer());
5110   const mcIdType *connI(_nodal_connec_index->begin());
5111   const double *coordsPtr(_coords->begin());
5112   bool isModified(false);
5113   for(mcIdType i=0;i<nbOfCells;i++)
5114     {
5115       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5116       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5117         {
5118           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5119           bool isQuadratic(cm.isQuadratic());
5120           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5121             {
5122               isModified=true;
5123               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5124             }
5125         }
5126     }
5127   if(isModified)
5128     _nodal_connec->declareAsNew();
5129   updateTime();
5130 }
5131
5132 /*!
5133  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5134  *
5135  * \sa orientCorrectly2DCells
5136  */
5137 void MEDCouplingUMesh::changeOrientationOfCells()
5138 {
5139   int mdim(getMeshDimension());
5140   if(mdim!=2 && mdim!=1)
5141     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5142   mcIdType nbOfCells=getNumberOfCells();
5143   mcIdType *conn(_nodal_connec->getPointer());
5144   const mcIdType *connI(_nodal_connec_index->begin());
5145   if(mdim==2)
5146     {//2D
5147       for(mcIdType i=0;i<nbOfCells;i++)
5148         {
5149           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5150           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5151           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5152         }
5153     }
5154   else
5155     {//1D
5156       for(mcIdType i=0;i<nbOfCells;i++)
5157         {
5158           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5159           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5160           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5161         }
5162     }
5163 }
5164
5165 /*!
5166  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5167  * oriented facets. The normal vector of the facet should point out of the cell.
5168  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5169  *         is not cleared before filling in.
5170  *  \throw If \a this->getMeshDimension() != 3.
5171  *  \throw If \a this->getSpaceDimension() != 3.
5172  *  \throw If the coordinates array is not set.
5173  *  \throw If the nodal connectivity of cells is not defined.
5174  *
5175  *  \if ENABLE_EXAMPLES
5176  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5177  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5178  *  \endif
5179  */
5180 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5181 {
5182   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5183     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5184   mcIdType nbOfCells=getNumberOfCells();
5185   const mcIdType *conn=_nodal_connec->begin();
5186   const mcIdType *connI=_nodal_connec_index->begin();
5187   const double *coordsPtr=_coords->begin();
5188   for(mcIdType i=0;i<nbOfCells;i++)
5189     {
5190       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5191       if(type==INTERP_KERNEL::NORM_POLYHED)
5192         {
5193           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5194             cells.push_back(i);
5195         }
5196     }
5197 }
5198
5199 /*!
5200  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5201  * out of the cell.
5202  *  \throw If \a this->getMeshDimension() != 3.
5203  *  \throw If \a this->getSpaceDimension() != 3.
5204  *  \throw If the coordinates array is not set.
5205  *  \throw If the nodal connectivity of cells is not defined.
5206  *  \throw If the reparation fails.
5207  *
5208  *  \if ENABLE_EXAMPLES
5209  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5210  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5211  *  \endif
5212  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5213  */
5214 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5215 {
5216   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5217     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5218   mcIdType nbOfCells=getNumberOfCells();
5219   mcIdType *conn=_nodal_connec->getPointer();
5220   const mcIdType *connI=_nodal_connec_index->begin();
5221   const double *coordsPtr=_coords->begin();
5222   for(mcIdType i=0;i<nbOfCells;i++)
5223     {
5224       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5225       if(type==INTERP_KERNEL::NORM_POLYHED)
5226         {
5227           try
5228           {
5229               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5230                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5231           }
5232           catch(INTERP_KERNEL::Exception& e)
5233           {
5234               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5235               throw INTERP_KERNEL::Exception(oss.str());
5236           }
5237         }
5238     }
5239   updateTime();
5240 }
5241
5242 /*!
5243  * This method invert orientation of all cells in \a this.
5244  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5245  * This method only operates on the connectivity so coordinates are not touched at all.
5246  */
5247 void MEDCouplingUMesh::invertOrientationOfAllCells()
5248 {
5249   checkConnectivityFullyDefined();
5250   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5251   mcIdType *conn(_nodal_connec->getPointer());
5252   const mcIdType *conni(_nodal_connec_index->begin());
5253   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5254     {
5255       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5256       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5257       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5258         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5259     }
5260   updateTime();
5261 }
5262
5263 /*!
5264  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5265  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5266  * according to which the first facet of the cell should be oriented to have the normal vector
5267  * pointing out of cell.
5268  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5269  *         cells. The caller is to delete this array using decrRef() as it is no more
5270  *         needed.
5271  *  \throw If \a this->getMeshDimension() != 3.
5272  *  \throw If \a this->getSpaceDimension() != 3.
5273  *  \throw If the coordinates array is not set.
5274  *  \throw If the nodal connectivity of cells is not defined.
5275  *
5276  *  \if ENABLE_EXAMPLES
5277  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5278  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5279  *  \endif
5280  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5281  */
5282 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5283 {
5284   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5285   if(getMeshDimension()!=3)
5286     throw INTERP_KERNEL::Exception(msg);
5287   int spaceDim=getSpaceDimension();
5288   if(spaceDim!=3)
5289     throw INTERP_KERNEL::Exception(msg);
5290   //
5291   mcIdType nbOfCells=getNumberOfCells();
5292   mcIdType *conn=_nodal_connec->getPointer();
5293   const mcIdType *connI=_nodal_connec_index->begin();
5294   const double *coo=getCoords()->begin();
5295   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5296   for(mcIdType i=0;i<nbOfCells;i++)
5297     {
5298       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5299       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5300         {
5301           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5302             {
5303               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5304               cells->pushBackSilent(i);
5305             }
5306         }
5307     }
5308   return cells.retn();
5309 }
5310
5311 /*!
5312  * This method is a faster method to correct orientation of all 3D cells in \a this.
5313  * 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.
5314  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5315  *
5316  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5317  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5318  */
5319 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5320 {
5321   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5322     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5323   mcIdType nbOfCells=getNumberOfCells();
5324   mcIdType *conn=_nodal_connec->getPointer();
5325   const mcIdType *connI=_nodal_connec_index->begin();
5326   const double *coordsPtr=_coords->begin();
5327   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5328   for(mcIdType i=0;i<nbOfCells;i++)
5329     {
5330       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5331       switch(type)
5332       {
5333         case INTERP_KERNEL::NORM_TETRA4:
5334           {
5335             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5336               {
5337                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5338                 ret->pushBackSilent(i);
5339               }
5340             break;
5341           }
5342         case INTERP_KERNEL::NORM_PYRA5:
5343           {
5344             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5345               {
5346                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5347                 ret->pushBackSilent(i);
5348               }
5349             break;
5350           }
5351         case INTERP_KERNEL::NORM_PENTA6:
5352         case INTERP_KERNEL::NORM_HEXA8:
5353         case INTERP_KERNEL::NORM_HEXGP12:
5354           {
5355             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5356               {
5357                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5358                 ret->pushBackSilent(i);
5359               }
5360             break;
5361           }
5362         case INTERP_KERNEL::NORM_POLYHED:
5363           {
5364             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5365               {
5366                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5367                 ret->pushBackSilent(i);
5368               }
5369             break;
5370           }
5371         default:
5372           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 !");
5373       }
5374     }
5375   updateTime();
5376   return ret.retn();
5377 }
5378
5379 /*!
5380  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5381  * If it is not the case an exception will be thrown.
5382  * This method is fast because the first cell of \a this is used to compute the plane.
5383  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5384  * \param pos output of size at least 3 used to store a point owned of searched plane.
5385  */
5386 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5387 {
5388   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5389     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5390   const mcIdType *conn=_nodal_connec->begin();
5391   const mcIdType *connI=_nodal_connec_index->begin();
5392   const double *coordsPtr=_coords->begin();
5393   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5394   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5395 }
5396
5397 /*!
5398  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5399  * cells. Currently cells of the following types are treated:
5400  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5401  * For a cell of other type an exception is thrown.
5402  * Space dimension of a 2D mesh can be either 2 or 3.
5403  * The Edge Ratio of a cell \f$t\f$ is:
5404  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5405  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5406  *  the smallest edge lengths of \f$t\f$.
5407  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5408  *          cells and one time, lying on \a this mesh. The caller is to delete this
5409  *          field using decrRef() as it is no more needed.
5410  *  \throw If the coordinates array is not set.
5411  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5412  *  \throw If the connectivity data array has more than one component.
5413  *  \throw If the connectivity data array has a named component.
5414  *  \throw If the connectivity index data array has more than one component.
5415  *  \throw If the connectivity index data array has a named component.
5416  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5417  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5418  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5419  */
5420 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5421 {
5422   checkConsistencyLight();
5423   int spaceDim=getSpaceDimension();
5424   int meshDim=getMeshDimension();
5425   if(spaceDim!=2 && spaceDim!=3)
5426     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5427   if(meshDim!=2 && meshDim!=3)
5428     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5429   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5430   ret->setMesh(this);
5431   mcIdType nbOfCells=getNumberOfCells();
5432   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5433   arr->alloc(nbOfCells,1);
5434   double *pt=arr->getPointer();
5435   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5436   const mcIdType *conn=_nodal_connec->begin();
5437   const mcIdType *connI=_nodal_connec_index->begin();
5438   const double *coo=_coords->begin();
5439   double tmp[12];
5440   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5441     {
5442       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5443       switch(t)
5444       {
5445         case INTERP_KERNEL::NORM_TRI3:
5446           {
5447             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5448             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5449             break;
5450           }
5451         case INTERP_KERNEL::NORM_QUAD4:
5452           {
5453             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5454             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5455             break;
5456           }
5457         case INTERP_KERNEL::NORM_TETRA4:
5458           {
5459             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5460             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5461             break;
5462           }
5463         default:
5464           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5465       }
5466       conn+=connI[i+1]-connI[i];
5467     }
5468   ret->setName("EdgeRatio");
5469   ret->synchronizeTimeWithSupport();
5470   return ret.retn();
5471 }
5472
5473 /*!
5474  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5475  * cells. Currently cells of the following types are treated:
5476  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5477  * For a cell of other type an exception is thrown.
5478  * Space dimension of a 2D mesh can be either 2 or 3.
5479  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5480  *          cells and one time, lying on \a this mesh. The caller is to delete this
5481  *          field using decrRef() as it is no more needed.
5482  *  \throw If the coordinates array is not set.
5483  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5484  *  \throw If the connectivity data array has more than one component.
5485  *  \throw If the connectivity data array has a named component.
5486  *  \throw If the connectivity index data array has more than one component.
5487  *  \throw If the connectivity index data array has a named component.
5488  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5489  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5490  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5491  */
5492 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5493 {
5494   checkConsistencyLight();
5495   int spaceDim=getSpaceDimension();
5496   int meshDim=getMeshDimension();
5497   if(spaceDim!=2 && spaceDim!=3)
5498     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5499   if(meshDim!=2 && meshDim!=3)
5500     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5501   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5502   ret->setMesh(this);
5503   mcIdType nbOfCells=getNumberOfCells();
5504   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5505   arr->alloc(nbOfCells,1);
5506   double *pt=arr->getPointer();
5507   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5508   const mcIdType *conn=_nodal_connec->begin();
5509   const mcIdType *connI=_nodal_connec_index->begin();
5510   const double *coo=_coords->begin();
5511   double tmp[12];
5512   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5513     {
5514       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5515       switch(t)
5516       {
5517         case INTERP_KERNEL::NORM_TRI3:
5518           {
5519             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5520             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5521             break;
5522           }
5523         case INTERP_KERNEL::NORM_QUAD4:
5524           {
5525             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5526             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5527             break;
5528           }
5529         case INTERP_KERNEL::NORM_TETRA4:
5530           {
5531             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5532             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5533             break;
5534           }
5535         default:
5536           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5537       }
5538       conn+=connI[i+1]-connI[i];
5539     }
5540   ret->setName("AspectRatio");
5541   ret->synchronizeTimeWithSupport();
5542   return ret.retn();
5543 }
5544
5545 /*!
5546  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5547  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5548  * in 3D space. Currently only cells of the following types are
5549  * treated: INTERP_KERNEL::NORM_QUAD4.
5550  * For a cell of other type an exception is thrown.
5551  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5552  * Defining
5553  * \f$t=\vec{da}\times\vec{ab}\f$,
5554  * \f$u=\vec{ab}\times\vec{bc}\f$
5555  * \f$v=\vec{bc}\times\vec{cd}\f$
5556  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5557  *  \f[
5558  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5559  *  \f]
5560  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5561  *          cells and one time, lying on \a this mesh. The caller is to delete this
5562  *          field using decrRef() as it is no more needed.
5563  *  \throw If the coordinates array is not set.
5564  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5565  *  \throw If the connectivity data array has more than one component.
5566  *  \throw If the connectivity data array has a named component.
5567  *  \throw If the connectivity index data array has more than one component.
5568  *  \throw If the connectivity index data array has a named component.
5569  *  \throw If \a this->getMeshDimension() != 2.
5570  *  \throw If \a this->getSpaceDimension() != 3.
5571  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5572  */
5573 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5574 {
5575   checkConsistencyLight();
5576   int spaceDim=getSpaceDimension();
5577   int meshDim=getMeshDimension();
5578   if(spaceDim!=3)
5579     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5580   if(meshDim!=2)
5581     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5582   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5583   ret->setMesh(this);
5584   mcIdType nbOfCells=getNumberOfCells();
5585   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5586   arr->alloc(nbOfCells,1);
5587   double *pt=arr->getPointer();
5588   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5589   const mcIdType *conn=_nodal_connec->begin();
5590   const mcIdType *connI=_nodal_connec_index->begin();
5591   const double *coo=_coords->begin();
5592   double tmp[12];
5593   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5594     {
5595       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5596       switch(t)
5597       {
5598         case INTERP_KERNEL::NORM_QUAD4:
5599           {
5600             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5601             *pt=INTERP_KERNEL::quadWarp(tmp);
5602             break;
5603           }
5604         default:
5605           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5606       }
5607       conn+=connI[i+1]-connI[i];
5608     }
5609   ret->setName("Warp");
5610   ret->synchronizeTimeWithSupport();
5611   return ret.retn();
5612 }
5613
5614
5615 /*!
5616  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5617  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5618  * treated: INTERP_KERNEL::NORM_QUAD4.
5619  * The skew is computed as follow for a quad with points (a,b,c,d): let
5620  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5621  * then the skew is computed as:
5622  *  \f[
5623  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5624  *  \f]
5625  *
5626  * For a cell of other type an exception is thrown.
5627  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5628  *          cells and one time, lying on \a this mesh. The caller is to delete this
5629  *          field using decrRef() as it is no more needed.
5630  *  \throw If the coordinates array is not set.
5631  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5632  *  \throw If the connectivity data array has more than one component.
5633  *  \throw If the connectivity data array has a named component.
5634  *  \throw If the connectivity index data array has more than one component.
5635  *  \throw If the connectivity index data array has a named component.
5636  *  \throw If \a this->getMeshDimension() != 2.
5637  *  \throw If \a this->getSpaceDimension() != 3.
5638  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5639  */
5640 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5641 {
5642   checkConsistencyLight();
5643   int spaceDim=getSpaceDimension();
5644   int meshDim=getMeshDimension();
5645   if(spaceDim!=3)
5646     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5647   if(meshDim!=2)
5648     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5649   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5650   ret->setMesh(this);
5651   mcIdType nbOfCells=getNumberOfCells();
5652   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5653   arr->alloc(nbOfCells,1);
5654   double *pt=arr->getPointer();
5655   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5656   const mcIdType *conn=_nodal_connec->begin();
5657   const mcIdType *connI=_nodal_connec_index->begin();
5658   const double *coo=_coords->begin();
5659   double tmp[12];
5660   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5661     {
5662       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5663       switch(t)
5664       {
5665         case INTERP_KERNEL::NORM_QUAD4:
5666           {
5667             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5668             *pt=INTERP_KERNEL::quadSkew(tmp);
5669             break;
5670           }
5671         default:
5672           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5673       }
5674       conn+=connI[i+1]-connI[i];
5675     }
5676   ret->setName("Skew");
5677   ret->synchronizeTimeWithSupport();
5678   return ret.retn();
5679 }
5680
5681 /*!
5682  * 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.
5683  *
5684  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5685  *
5686  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5687  */
5688 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5689 {
5690   checkConsistencyLight();
5691   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5692   ret->setMesh(this);
5693   std::set<INTERP_KERNEL::NormalizedCellType> types;
5694   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5695   int spaceDim(getSpaceDimension());
5696   mcIdType nbCells(getNumberOfCells());
5697   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5698   arr->alloc(nbCells,1);
5699   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5700     {
5701       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5702       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5703       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5704     }
5705   ret->setArray(arr);
5706   ret->setName("Diameter");
5707   return ret.retn();
5708 }
5709
5710 /*!
5711  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5712  *
5713  * \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)
5714  *                         For all other cases this input parameter is ignored.
5715  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5716  *
5717  * \throw If \a this is not fully set (coordinates and connectivity).
5718  * \throw If a cell in \a this has no valid nodeId.
5719  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5720  */
5721 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5722 {
5723   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5724   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.
5725     return getBoundingBoxForBBTreeFast();
5726   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5727     {
5728       bool presenceOfQuadratic(false);
5729       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5730         {
5731           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5732           if(cm.isQuadratic())
5733             presenceOfQuadratic=true;
5734         }
5735       if(!presenceOfQuadratic)
5736         return getBoundingBoxForBBTreeFast();
5737       if(mDim==2 && sDim==2)
5738         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5739       else
5740         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5741     }
5742   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) !");
5743 }
5744
5745 /*!
5746  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5747  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5748  *
5749  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5750  *
5751  * \throw If \a this is not fully set (coordinates and connectivity).
5752  * \throw If a cell in \a this has no valid nodeId.
5753  */
5754 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5755 {
5756   checkFullyDefined();
5757   int spaceDim(getSpaceDimension());
5758   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5759   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5760   double *bbox(ret->getPointer());
5761   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5762     {
5763       bbox[2*i]=std::numeric_limits<double>::max();
5764       bbox[2*i+1]=-std::numeric_limits<double>::max();
5765     }
5766   const double *coordsPtr(_coords->begin());
5767   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5768   for(mcIdType i=0;i<nbOfCells;i++)
5769     {
5770       mcIdType offset=connI[i]+1;
5771       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5772       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5773         {
5774           mcIdType nodeId=conn[offset+j];
5775           if(nodeId>=0 && nodeId<nbOfNodes)
5776             {
5777               for(int k=0;k<spaceDim;k++)
5778                 {
5779                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5780                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5781                 }
5782               kk++;
5783             }
5784         }
5785       if(kk==0)
5786         {
5787           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5788           throw INTERP_KERNEL::Exception(oss.str());
5789         }
5790     }
5791   return ret.retn();
5792 }
5793
5794 /*!
5795  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5796  * useful for 2D meshes having quadratic cells
5797  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5798  * the two extremities of the arc of circle).
5799  *
5800  * \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)
5801  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5802  * \throw If \a this is not fully defined.
5803  * \throw If \a this is not a mesh with meshDimension equal to 2.
5804  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5805  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5806  */
5807 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5808 {
5809   checkFullyDefined();
5810   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5811
5812   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5813   mcIdType nbOfCells=getNumberOfCells();
5814   if(spaceDim!=2 || mDim!=2)
5815     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!");
5816   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5817   double *bbox(ret->getPointer());
5818   const double *coords(_coords->begin());
5819   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5820   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5821     {
5822       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5823       mcIdType sz(connI[1]-connI[0]-1);
5824       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5825       INTERP_KERNEL::QuadraticPolygon *pol(0);
5826       for(mcIdType j=0;j<sz;j++)
5827         {
5828           mcIdType nodeId(conn[*connI+1+j]);
5829           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5830         }
5831       if(!cm.isQuadratic())
5832         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5833       else
5834         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5835       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5836       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5837     }
5838   return ret.retn();
5839 }
5840
5841 /*!
5842  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5843  * useful for 2D meshes having quadratic cells
5844  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5845  * the two extremities of the arc of circle).
5846  *
5847  * \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)
5848  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5849  * \throw If \a this is not fully defined.
5850  * \throw If \a this is not a mesh with meshDimension equal to 1.
5851  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5852  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5853  */
5854 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5855 {
5856   checkFullyDefined();
5857   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5858   mcIdType nbOfCells=getNumberOfCells();
5859   if(spaceDim!=2 || mDim!=1)
5860     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!");
5861   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5862   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5863   double *bbox(ret->getPointer());
5864   const double *coords(_coords->begin());
5865   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5866   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5867     {
5868       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5869       mcIdType sz(connI[1]-connI[0]-1);
5870       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5871       INTERP_KERNEL::Edge *edge(0);
5872       for(mcIdType j=0;j<sz;j++)
5873         {
5874           mcIdType nodeId(conn[*connI+1+j]);
5875           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5876         }
5877       if(!cm.isQuadratic())
5878         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5879       else
5880         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5881       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5882       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5883     }
5884   return ret.retn();
5885 }
5886
5887 /// @cond INTERNAL
5888
5889 namespace MEDCouplingImpl
5890 {
5891   class ConnReader
5892   {
5893   public:
5894     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5895     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5896   private:
5897     const mcIdType *_conn;
5898     mcIdType _val;
5899   };
5900
5901   class ConnReader2
5902   {
5903   public:
5904     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5905     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5906   private:
5907     const mcIdType *_conn;
5908     mcIdType _val;
5909   };
5910 }
5911
5912 /// @endcond
5913
5914 /*!
5915  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5916  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5917  * \a this is composed in cell types.
5918  * The returned array is of size 3*n where n is the number of different types present in \a this.
5919  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5920  * This parameter is kept only for compatibility with other method listed above.
5921  */
5922 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5923 {
5924   checkConnectivityFullyDefined();
5925   const mcIdType *conn=_nodal_connec->begin();
5926   const mcIdType *connI=_nodal_connec_index->begin();
5927   const mcIdType *work=connI;
5928   mcIdType nbOfCells=getNumberOfCells();
5929   std::size_t n=getAllGeoTypes().size();
5930   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5931   std::set<INTERP_KERNEL::NormalizedCellType> types;
5932   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5933     {
5934       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5935       if(types.find(typ)!=types.end())
5936         {
5937           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5938           oss << " is not contiguous !";
5939           throw INTERP_KERNEL::Exception(oss.str());
5940         }
5941       types.insert(typ);
5942       ret[3*i]=typ;
5943       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5944       ret[3*i+1]=ToIdType(std::distance(work,work2));
5945       work=work2;
5946     }
5947   return ret;
5948 }
5949
5950 /*!
5951  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5952  * only for types cell, type node is not managed.
5953  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5954  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5955  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5956  * If 2 or more same geometric type is in \a code and exception is thrown too.
5957  *
5958  * This method firstly checks
5959  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5960  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5961  * an exception is thrown too.
5962  *
5963  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5964  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5965  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5966  */
5967 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5968 {
5969   if(code.empty())
5970     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5971   std::size_t sz=code.size();
5972   std::size_t n=sz/3;
5973   if(sz%3!=0)
5974     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5975   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5976   mcIdType nb=0;
5977   bool isNoPflUsed=true;
5978   for(std::size_t i=0;i<n;i++)
5979     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5980       {
5981         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5982         nb+=code[3*i+1];
5983         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5984           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5985         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5986       }
5987   if(types.size()!=n)
5988     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5989   if(isNoPflUsed)
5990     {
5991       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5992         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5993       if(types.size()==_types.size())
5994         return 0;
5995     }
5996   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5997   ret->alloc(nb,1);
5998   mcIdType *retPtr=ret->getPointer();
5999   const mcIdType *connI=_nodal_connec_index->begin();
6000   const mcIdType *conn=_nodal_connec->begin();
6001   mcIdType nbOfCells=getNumberOfCells();
6002   const mcIdType *i=connI;
6003   int kk=0;
6004   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6005     {
6006       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
6007       mcIdType offset=ToIdType(std::distance(connI,i));
6008       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
6009       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
6010       if(code[3*kk+2]==-1)
6011         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
6012           *retPtr++=k+offset;
6013       else
6014         {
6015           mcIdType idInIdsPerType=code[3*kk+2];
6016           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
6017             {
6018               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
6019               if(zePfl)
6020                 {
6021                   zePfl->checkAllocated();
6022                   if(zePfl->getNumberOfComponents()==1)
6023                     {
6024                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
6025                         {
6026                           if(*k>=0 && *k<nbOfCellsOfCurType)
6027                             *retPtr=(*k)+offset;
6028                           else
6029                             {
6030                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
6031                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
6032                               throw INTERP_KERNEL::Exception(oss.str());
6033                             }
6034                         }
6035                     }
6036                   else
6037                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
6038                 }
6039               else
6040                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
6041             }
6042           else
6043             {
6044               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
6045               oss << " should be in [0," << idsPerType.size() << ") !";
6046               throw INTERP_KERNEL::Exception(oss.str());
6047             }
6048         }
6049       i=j;
6050     }
6051   return ret.retn();
6052 }
6053
6054 /*!
6055  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
6056  * 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.
6057  * 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.
6058  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
6059  *
6060  * \param [in] profile list of IDs constituing the profile
6061  * \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.
6062  * \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,
6063  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
6064  * \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.
6065  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
6066  * \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
6067  */
6068 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
6069 {
6070   if(!profile)
6071     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
6072   if(profile->getNumberOfComponents()!=1)
6073     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
6074   checkConnectivityFullyDefined();
6075   const mcIdType *conn=_nodal_connec->begin();
6076   const mcIdType *connI=_nodal_connec_index->begin();
6077   mcIdType nbOfCells=getNumberOfCells();
6078   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6079   std::vector<mcIdType> typeRangeVals(1);
6080   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6081     {
6082       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6083       if(std::find(types.begin(),types.end(),curType)!=types.end())
6084         {
6085           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
6086         }
6087       types.push_back(curType);
6088       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6089       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
6090     }
6091   //
6092   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
6093   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
6094   MCAuto<DataArrayIdType> tmp0=castArr;
6095   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
6096   MCAuto<DataArrayIdType> tmp2=castsPresent;
6097   //
6098   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6099   code.resize(3*nbOfCastsFinal);
6100   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6101   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6102   for(mcIdType i=0;i<nbOfCastsFinal;i++)
6103     {
6104       mcIdType castId=castsPresent->getIJ(i,0);
6105       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6106       idsInPflPerType2.push_back(tmp3);
6107       code[3*i]=ToIdType(types[castId]);
6108       code[3*i+1]=tmp3->getNumberOfTuples();
6109       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6110       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6111         {
6112           tmp4->copyStringInfoFrom(*profile);
6113           idsPerType2.push_back(tmp4);
6114           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6115         }
6116       else
6117         {
6118           code[3*i+2]=-1;
6119         }
6120     }
6121   std::size_t sz2=idsInPflPerType2.size();
6122   idsInPflPerType.resize(sz2);
6123   for(std::size_t i=0;i<sz2;i++)
6124     {
6125       DataArrayIdType *locDa=idsInPflPerType2[i];
6126       locDa->incrRef();
6127       idsInPflPerType[i]=locDa;
6128     }
6129   std::size_t sz=idsPerType2.size();
6130   idsPerType.resize(sz);
6131   for(std::size_t i=0;i<sz;i++)
6132     {
6133       DataArrayIdType *locDa=idsPerType2[i];
6134       locDa->incrRef();
6135       idsPerType[i]=locDa;
6136     }
6137 }
6138
6139 /*!
6140  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6141  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6142  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6143  * 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.
6144  */
6145 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6146 {
6147   checkFullyDefined();
6148   nM1LevMesh->checkFullyDefined();
6149   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6150     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6151   if(_coords!=nM1LevMesh->getCoords())
6152     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6153   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6154   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6155   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6156   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6157   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6158   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6159   tmp->setConnectivity(tmp0,tmp1);
6160   tmp->renumberCells(ret0->begin(),false);
6161   revDesc=tmp->getNodalConnectivity();
6162   revDescIndx=tmp->getNodalConnectivityIndex();
6163   DataArrayIdType *ret=0;
6164   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6165     {
6166       mcIdType tmp2;
6167       ret->getMaxValue(tmp2);
6168       ret->decrRef();
6169       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6170       throw INTERP_KERNEL::Exception(oss.str());
6171     }
6172   nM1LevMeshIds=ret;
6173   //
6174   revDesc->incrRef();
6175   revDescIndx->incrRef();
6176   ret1->incrRef();
6177   ret0->incrRef();
6178   meshnM1Old2New=ret0;
6179   return ret1;
6180 }
6181
6182 /*!
6183  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6184  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6185  * in "Old to New" mode.
6186  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6187  *          this array using decrRef() as it is no more needed.
6188  *  \throw If the nodal connectivity of cells is not defined.
6189  */
6190 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6191 {
6192   checkConnectivityFullyDefined();
6193   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6194   renumberCells(ret->begin(),false);
6195   return ret.retn();
6196 }
6197
6198 /*!
6199  * This methods checks that cells are sorted by their types.
6200  * This method makes asumption (no check) that connectivity is correctly set before calling.
6201  */
6202 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6203 {
6204   checkFullyDefined();
6205   const mcIdType *conn=_nodal_connec->begin();
6206   const mcIdType *connI=_nodal_connec_index->begin();
6207   mcIdType nbOfCells=getNumberOfCells();
6208   std::set<INTERP_KERNEL::NormalizedCellType> types;
6209   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6210     {
6211       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6212       if(types.find(curType)!=types.end())
6213         return false;
6214       types.insert(curType);
6215       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6216     }
6217   return true;
6218 }
6219
6220 /*!
6221  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6222  * The geometric type order is specified by MED file.
6223  *
6224  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6225  */
6226 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6227 {
6228   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6229 }
6230
6231 /*!
6232  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6233  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6234  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6235  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6236  */
6237 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6238 {
6239   checkFullyDefined();
6240   const mcIdType *conn=_nodal_connec->begin();
6241   const mcIdType *connI=_nodal_connec_index->begin();
6242   mcIdType nbOfCells=getNumberOfCells();
6243   if(nbOfCells==0)
6244     return true;
6245   mcIdType lastPos=-1;
6246   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6247   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6248     {
6249       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6250       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6251       if(isTypeExists!=orderEnd)
6252         {
6253           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6254           if(pos<=lastPos)
6255             return false;
6256           lastPos=pos;
6257           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6258         }
6259       else
6260         {
6261           if(sg.find(curType)==sg.end())
6262             {
6263               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6264               sg.insert(curType);
6265             }
6266           else
6267             return false;
6268         }
6269     }
6270   return true;
6271 }
6272
6273 /*!
6274  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6275  * 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
6276  * 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'.
6277  */
6278 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6279 {
6280   checkConnectivityFullyDefined();
6281   mcIdType nbOfCells=getNumberOfCells();
6282   const mcIdType *conn=_nodal_connec->begin();
6283   const mcIdType *connI=_nodal_connec_index->begin();
6284   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6285   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6286   tmpa->alloc(nbOfCells,1);
6287   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6288   tmpb->fillWithZero();
6289   mcIdType *tmp=tmpa->getPointer();
6290   mcIdType *tmp2=tmpb->getPointer();
6291   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6292     {
6293       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6294       if(where!=orderEnd)
6295         {
6296           mcIdType pos=ToIdType(std::distance(orderBg,where));
6297           tmp2[pos]++;
6298           tmp[std::distance(connI,i)]=pos;
6299         }
6300       else
6301         {
6302           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6303           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6304           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6305           throw INTERP_KERNEL::Exception(oss.str());
6306         }
6307     }
6308   nbPerType=tmpb.retn();
6309   return tmpa.retn();
6310 }
6311
6312 /*!
6313  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6314  *
6315  * \return a new object containing the old to new correspondence.
6316  *
6317  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6318  */
6319 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6320 {
6321   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6322 }
6323
6324 /*!
6325  * 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.
6326  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6327  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6328  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6329  */
6330 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6331 {
6332   DataArrayIdType *nbPerType=0;
6333   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6334   nbPerType->decrRef();
6335   return tmpa->buildPermArrPerLevel();
6336 }
6337
6338 /*!
6339  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6340  * The number of cells remains unchanged after the call of this method.
6341  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6342  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6343  *
6344  * \return the array giving the correspondence old to new.
6345  */
6346 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6347 {
6348   checkFullyDefined();
6349   computeTypes();
6350   const mcIdType *conn=_nodal_connec->begin();
6351   const mcIdType *connI=_nodal_connec_index->begin();
6352   mcIdType nbOfCells=getNumberOfCells();
6353   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6354   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6355     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6356       {
6357         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6358         types.push_back(curType);
6359         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6360       }
6361   DataArrayIdType *ret=DataArrayIdType::New();
6362   ret->alloc(nbOfCells,1);
6363   mcIdType *retPtr=ret->getPointer();
6364   std::fill(retPtr,retPtr+nbOfCells,-1);
6365   mcIdType newCellId=0;
6366   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6367     {
6368       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6369         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6370           retPtr[std::distance(connI,i)]=newCellId++;
6371     }
6372   renumberCells(retPtr,false);
6373   return ret;
6374 }
6375
6376 /*!
6377  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6378  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6379  * This method makes asumption that connectivity is correctly set before calling.
6380  */
6381 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6382 {
6383   checkConnectivityFullyDefined();
6384   const mcIdType *conn=_nodal_connec->begin();
6385   const mcIdType *connI=_nodal_connec_index->begin();
6386   mcIdType nbOfCells=getNumberOfCells();
6387   std::vector<MEDCouplingUMesh *> ret;
6388   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6389     {
6390       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6391       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6392       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6393       mcIdType endCellId=ToIdType(std::distance(connI,i));
6394       mcIdType sz=endCellId-beginCellId;
6395       mcIdType *cells=new mcIdType[sz];
6396       for(mcIdType j=0;j<sz;j++)
6397         cells[j]=beginCellId+j;
6398       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6399       delete [] cells;
6400       ret.push_back(m);
6401     }
6402   return ret;
6403 }
6404
6405 /*!
6406  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6407  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6408  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6409  *
6410  * \return a newly allocated instance, that the caller must manage.
6411  * \throw If \a this contains more than one geometric type.
6412  * \throw If the nodal connectivity of \a this is not fully defined.
6413  * \throw If the internal data is not coherent.
6414  */
6415 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6416 {
6417   checkConnectivityFullyDefined();
6418   if(_types.size()!=1)
6419     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6420   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6421   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6422   ret->setCoords(getCoords());
6423   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6424   if(retC)
6425     {
6426       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6427       retC->setNodalConnectivity(c);
6428     }
6429   else
6430     {
6431       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6432       if(!retD)
6433         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6434       DataArrayIdType *c=0,*ci=0;
6435       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6436       MCAuto<DataArrayIdType> cs(c),cis(ci);
6437       retD->setNodalConnectivity(cs,cis);
6438     }
6439   return ret.retn();
6440 }
6441
6442 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6443 {
6444   checkConnectivityFullyDefined();
6445   if(_types.size()!=1)
6446     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6447   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6448   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6449   if(cm.isDynamic())
6450     {
6451       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6452       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6453       throw INTERP_KERNEL::Exception(oss.str());
6454     }
6455   mcIdType nbCells=getNumberOfCells();
6456   mcIdType typi=ToIdType(typ);
6457   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6458   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6459   mcIdType *outPtr=connOut->getPointer();
6460   const mcIdType *conn=_nodal_connec->begin();
6461   const mcIdType *connI=_nodal_connec_index->begin();
6462   nbNodesPerCell++;
6463   for(mcIdType i=0;i<nbCells;i++,connI++)
6464     {
6465       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6466         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6467       else
6468         {
6469           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 << ") !";
6470           throw INTERP_KERNEL::Exception(oss.str());
6471         }
6472     }
6473   return connOut.retn();
6474 }
6475
6476 /*!
6477  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6478  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6479  * \param nodalConn nodal connectivity
6480  * \param nodalConnIndex nodal connectivity indices
6481  */
6482 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6483 {
6484   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6485   checkConnectivityFullyDefined();
6486   if(_types.size()!=1)
6487     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6488   mcIdType nbCells=getNumberOfCells(),
6489            lgth=_nodal_connec->getNumberOfTuples();
6490   if(lgth<nbCells)
6491     throw INTERP_KERNEL::Exception(msg0);
6492   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6493   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6494   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6495   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6496   cip[0]=0;
6497   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6498     {
6499       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6500       mcIdType delta(stop-strt);
6501       if(delta>=1)
6502         {
6503           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6504             cp=std::copy(incp+strt,incp+stop,cp);
6505           else
6506             throw INTERP_KERNEL::Exception(msg0);
6507         }
6508       else
6509         throw INTERP_KERNEL::Exception(msg0);
6510       cip[1]=cip[0]+delta;
6511     }
6512   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6513 }
6514
6515 /*!
6516  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6517  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6518  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6519  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6520  * are not used here to avoid the build of big permutation array.
6521  *
6522  * \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
6523  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6524  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6525  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6526  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6527  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6528  * \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
6529  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6530  */
6531 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6532                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6533                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6534 {
6535   std::vector<const MEDCouplingUMesh *> ms2;
6536   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6537     if(*it)
6538       {
6539         (*it)->checkConnectivityFullyDefined();
6540         ms2.push_back(*it);
6541       }
6542   if(ms2.empty())
6543     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6544   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6545   int meshDim=ms2[0]->getMeshDimension();
6546   std::vector<const MEDCouplingUMesh *> m1ssm;
6547   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6548   //
6549   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6550   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6551   mcIdType fake=0,rk=0;
6552   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6553   ret1->alloc(0,1); ret2->alloc(0,1);
6554   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6555     {
6556       if(meshDim!=(*it)->getMeshDimension())
6557         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6558       if(refCoo!=(*it)->getCoords())
6559         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6560       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6561       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6562       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6563       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6564         {
6565           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6566           m1ssmSingleAuto.push_back(singleCell);
6567           m1ssmSingle.push_back(singleCell);
6568           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6569         }
6570     }
6571   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6572   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6573   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6574   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6575     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6576   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6577   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6578   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6579   return ret0.retn();
6580 }
6581
6582 /*!
6583  * This method returns a newly created DataArrayIdType instance.
6584  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6585  */
6586 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6587 {
6588   checkFullyDefined();
6589   const mcIdType *conn=_nodal_connec->begin();
6590   const mcIdType *connIndex=_nodal_connec_index->begin();
6591   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6592   for(const mcIdType *w=begin;w!=end;w++)
6593     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6594       ret->pushBackSilent(*w);
6595   return ret.retn();
6596 }
6597
6598 /*!
6599  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6600  * are in [0:getNumberOfCells())
6601  */
6602 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6603 {
6604   checkFullyDefined();
6605   const mcIdType *conn=_nodal_connec->begin();
6606   const mcIdType *connI=_nodal_connec_index->begin();
6607   mcIdType nbOfCells=getNumberOfCells();
6608   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6609   mcIdType *tmp=new mcIdType[nbOfCells];
6610   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6611     {
6612       mcIdType j=0;
6613       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6614         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6615           tmp[std::distance(connI,i)]=j++;
6616     }
6617   DataArrayIdType *ret=DataArrayIdType::New();
6618   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6619   ret->copyStringInfoFrom(*da);
6620   mcIdType *retPtr=ret->getPointer();
6621   const mcIdType *daPtr=da->begin();
6622   mcIdType nbOfElems=da->getNbOfElems();
6623   for(mcIdType k=0;k<nbOfElems;k++)
6624     retPtr[k]=tmp[daPtr[k]];
6625   delete [] tmp;
6626   return ret;
6627 }
6628
6629 /*!
6630  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6631  * This method \b works \b for mesh sorted by type.
6632  * cells whose ids is in 'idsPerGeoType' array.
6633  * This method conserves coords and name of mesh.
6634  */
6635 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6636 {
6637   std::vector<mcIdType> code=getDistributionOfTypes();
6638   std::size_t nOfTypesInThis=code.size()/3;
6639   mcIdType sz=0,szOfType=0;
6640   for(std::size_t i=0;i<nOfTypesInThis;i++)
6641     {
6642       if(code[3*i]!=type)
6643         sz+=code[3*i+1];
6644       else
6645         szOfType=code[3*i+1];
6646     }
6647   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6648     if(*work<0 || *work>=szOfType)
6649       {
6650         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6651         oss << ". It should be in [0," << szOfType << ") !";
6652         throw INTERP_KERNEL::Exception(oss.str());
6653       }
6654   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6655   mcIdType *idsPtr=idsTokeep->getPointer();
6656   mcIdType offset=0;
6657   for(std::size_t i=0;i<nOfTypesInThis;i++)
6658     {
6659       if(code[3*i]!=type)
6660         for(mcIdType j=0;j<code[3*i+1];j++)
6661           *idsPtr++=offset+j;
6662       else
6663         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6664       offset+=code[3*i+1];
6665     }
6666   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6667   ret->copyTinyInfoFrom(this);
6668   return ret.retn();
6669 }
6670
6671 /*!
6672  * This method returns a vector of size 'this->getNumberOfCells()'.
6673  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6674  */
6675 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6676 {
6677   mcIdType ncell=getNumberOfCells();
6678   std::vector<bool> ret(ncell);
6679   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6680   const mcIdType *c=getNodalConnectivity()->begin();
6681   for(mcIdType i=0;i<ncell;i++)
6682     {
6683       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6684       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6685       ret[i]=cm.isQuadratic();
6686     }
6687   return ret;
6688 }
6689
6690 /*!
6691  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6692  */
6693 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6694 {
6695   if(other->getType()!=UNSTRUCTURED)
6696     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6697   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6698   return MergeUMeshes(this,otherC);
6699 }
6700
6701 /*!
6702  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6703  * computed by averaging coordinates of cell nodes, so this method is not a right
6704  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6705  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6706  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6707  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6708  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6709  *          components. The caller is to delete this array using decrRef() as it is
6710  *          no more needed.
6711  *  \throw If the coordinates array is not set.
6712  *  \throw If the nodal connectivity of cells is not defined.
6713  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6714  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6715  */
6716 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6717 {
6718   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6719   int spaceDim=getSpaceDimension();
6720   mcIdType nbOfCells=getNumberOfCells();
6721   ret->alloc(nbOfCells,spaceDim);
6722   ret->copyStringInfoFrom(*getCoords());
6723   double *ptToFill=ret->getPointer();
6724   const mcIdType *nodal=_nodal_connec->begin();
6725   const mcIdType *nodalI=_nodal_connec_index->begin();
6726   const double *coor=_coords->begin();
6727   for(mcIdType i=0;i<nbOfCells;i++)
6728     {
6729       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6730       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6731       ptToFill+=spaceDim;
6732     }
6733   return ret.retn();
6734 }
6735
6736
6737 /*!
6738  * See computeCellCenterOfMass().
6739  *  \param eps a precision for the detection of degenerated arc of circles.
6740  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6741  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6742  *          components. The caller is to delete this array using decrRef() as it is
6743  *          no more needed.
6744  *  \throw If the coordinates array is not set.
6745  *  \throw If the nodal connectivity of cells is not defined.
6746  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6747  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6748  */
6749 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6750 {
6751   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6752   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6753   return ret.retn();
6754 }
6755
6756
6757 /*!
6758  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6759  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6760  *
6761  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6762  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6763  *
6764  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6765  * \throw If \a this is not fully defined (coordinates and connectivity)
6766  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6767  */
6768 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6769 {
6770   checkFullyDefined();
6771   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6772   int spaceDim=getSpaceDimension();
6773   mcIdType nbOfCells=getNumberOfCells();
6774   mcIdType nbOfNodes=getNumberOfNodes();
6775   ret->alloc(nbOfCells,spaceDim);
6776   double *ptToFill=ret->getPointer();
6777   const mcIdType *nodal=_nodal_connec->begin();
6778   const mcIdType *nodalI=_nodal_connec_index->begin();
6779   const double *coor=_coords->begin();
6780   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6781     {
6782       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6783       std::fill(ptToFill,ptToFill+spaceDim,0.);
6784       if(type!=INTERP_KERNEL::NORM_POLYHED)
6785         {
6786           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6787             {
6788               if(*conn>=0 && *conn<nbOfNodes)
6789                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6790               else
6791                 {
6792                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6793                   throw INTERP_KERNEL::Exception(oss.str());
6794                 }
6795             }
6796           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6797           if(nbOfNodesInCell>0)
6798             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6799           else
6800             {
6801               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6802               throw INTERP_KERNEL::Exception(oss.str());
6803             }
6804         }
6805       else
6806         {
6807           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6808           s.erase(-1);
6809           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6810             {
6811               if(*it>=0 && *it<nbOfNodes)
6812                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6813               else
6814                 {
6815                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6816                   throw INTERP_KERNEL::Exception(oss.str());
6817                 }
6818             }
6819           if(!s.empty())
6820             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6821           else
6822             {
6823               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6824               throw INTERP_KERNEL::Exception(oss.str());
6825             }
6826         }
6827     }
6828   return ret.retn();
6829 }
6830
6831 /*!
6832  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6833  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6834  * are specified via an array of cell ids.
6835  *  \warning Validity of the specified cell ids is not checked!
6836  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6837  *  \param [in] begin - an array of cell ids of interest.
6838  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6839  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6840  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6841  *          caller is to delete this array using decrRef() as it is no more needed.
6842  *  \throw If the coordinates array is not set.
6843  *  \throw If the nodal connectivity of cells is not defined.
6844  *
6845  *  \if ENABLE_EXAMPLES
6846  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6847  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6848  *  \endif
6849  */
6850 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6851 {
6852   DataArrayDouble *ret=DataArrayDouble::New();
6853   int spaceDim=getSpaceDimension();
6854   std::size_t nbOfTuple=std::distance(begin,end);
6855   ret->alloc(nbOfTuple,spaceDim);
6856   double *ptToFill=ret->getPointer();
6857   double *tmp=new double[spaceDim];
6858   const mcIdType *nodal=_nodal_connec->begin();
6859   const mcIdType *nodalI=_nodal_connec_index->begin();
6860   const double *coor=_coords->begin();
6861   for(const mcIdType *w=begin;w!=end;w++)
6862     {
6863       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6864       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6865       ptToFill+=spaceDim;
6866     }
6867   delete [] tmp;
6868   return ret;
6869 }
6870
6871 /*!
6872  * 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".
6873  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6874  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6875  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6876  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6877  *
6878  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6879  * \throw If spaceDim!=3 or meshDim!=2.
6880  * \throw If connectivity of \a this is invalid.
6881  * \throw If connectivity of a cell in \a this points to an invalid node.
6882  */
6883 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6884 {
6885   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6886   mcIdType nbOfCells=getNumberOfCells();
6887   mcIdType nbOfNodes(getNumberOfNodes());
6888   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6889     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6890   ret->alloc(nbOfCells,4);
6891   double *retPtr(ret->getPointer());
6892   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6893   const double *coor(_coords->begin());
6894   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6895     {
6896       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6897       if(nodalI[1]-nodalI[0]>=4)
6898         {
6899           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6900                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6901                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6902           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6903                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6904                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6905           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]};
6906           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]));
6907           for(int j=0;j<3;j++)
6908             {
6909               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6910               if(nodeId>=0 && nodeId<nbOfNodes)
6911                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6912               else
6913                 {
6914                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6915                   throw INTERP_KERNEL::Exception(oss.str());
6916                 }
6917             }
6918           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6919             {
6920               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6921               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6922             }
6923           else
6924             {
6925               if(nodalI[1]-nodalI[0]==4)
6926                 {
6927                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6928                   throw INTERP_KERNEL::Exception(oss.str());
6929                 }
6930               //
6931               double dd[3]={0.,0.,0.};
6932               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6933                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6934               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6935               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6936               std::copy(dd,dd+3,matrix+4*2);
6937               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6938               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6939             }
6940         }
6941       else
6942         {
6943           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6944           throw INTERP_KERNEL::Exception(oss.str());
6945         }
6946     }
6947   return ret.retn();
6948 }
6949
6950 /*!
6951  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6952  *
6953  */
6954 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6955 {
6956   if(!da)
6957     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6958   da->checkAllocated();
6959   std::string name(da->getName());
6960   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6961   if(name.empty())
6962     ret->setName("Mesh");
6963   ret->setCoords(da);
6964   mcIdType nbOfTuples(da->getNumberOfTuples());
6965   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6966   c->alloc(2*nbOfTuples,1);
6967   cI->alloc(nbOfTuples+1,1);
6968   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6969   *cip++=0;
6970   for(mcIdType i=0;i<nbOfTuples;i++)
6971     {
6972       *cp++=INTERP_KERNEL::NORM_POINT1;
6973       *cp++=i;
6974       *cip++=2*(i+1);
6975     }
6976   ret->setConnectivity(c,cI,true);
6977   return ret.retn();
6978 }
6979
6980 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6981 {
6982   if(!da)
6983     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6984   da->checkAllocated();
6985   std::string name(da->getName());
6986   MCAuto<MEDCouplingUMesh> ret;
6987   {
6988     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6989     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6990     arr->alloc(da->getNumberOfTuples());
6991     tmp->setCoordsAt(0,arr);
6992     ret=tmp->buildUnstructured();
6993   }
6994   ret->setCoords(da);
6995   if(name.empty())
6996     ret->setName("Mesh");
6997   else
6998     ret->setName(name);
6999   return ret;
7000 }
7001
7002 /*!
7003  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7004  * Cells and nodes of
7005  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7006  *  \param [in] mesh1 - the first mesh.
7007  *  \param [in] mesh2 - the second mesh.
7008  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7009  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7010  *          is no more needed.
7011  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7012  *  \throw If the coordinates array is not set in none of the meshes.
7013  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7014  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7015  */
7016 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7017 {
7018   std::vector<const MEDCouplingUMesh *> tmp(2);
7019   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7020   return MergeUMeshes(tmp);
7021 }
7022
7023 /*!
7024  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7025  * Cells and nodes of
7026  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7027  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7028  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7029  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7030  *          is no more needed.
7031  *  \throw If \a a.size() == 0.
7032  *  \throw If \a a[ *i* ] == NULL.
7033  *  \throw If the coordinates array is not set in none of the meshes.
7034  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7035  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7036  */
7037 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
7038 {
7039   std::size_t sz=a.size();
7040   if(sz==0)
7041     return MergeUMeshesLL(a);
7042   for(std::size_t ii=0;ii<sz;ii++)
7043     if(!a[ii])
7044       {
7045         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7046         throw INTERP_KERNEL::Exception(oss.str());
7047       }
7048   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7049   std::vector< const MEDCouplingUMesh * > aa(sz);
7050   int spaceDim=-3;
7051   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7052     {
7053       const MEDCouplingUMesh *cur=a[i];
7054       const DataArrayDouble *coo=cur->getCoords();
7055       if(coo)
7056         spaceDim=int(coo->getNumberOfComponents());
7057     }
7058   if(spaceDim==-3)
7059     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7060   for(std::size_t i=0;i<sz;i++)
7061     {
7062       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7063       aa[i]=bb[i];
7064     }
7065   return MergeUMeshesLL(aa);
7066 }
7067
7068 /*!
7069  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
7070  * dimension and sharing the node coordinates array.
7071  * All cells of the first mesh precede all cells of the second mesh
7072  * within the result mesh.
7073  *  \param [in] mesh1 - the first mesh.
7074  *  \param [in] mesh2 - the second mesh.
7075  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7076  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7077  *          is no more needed.
7078  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7079  *  \throw If the meshes do not share the node coordinates array.
7080  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7081  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7082  */
7083 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7084 {
7085   std::vector<const MEDCouplingUMesh *> tmp(2);
7086   tmp[0]=mesh1; tmp[1]=mesh2;
7087   return MergeUMeshesOnSameCoords(tmp);
7088 }
7089
7090 /*!
7091  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7092  * dimension and sharing the node coordinates array.
7093  * All cells of the *i*-th mesh precede all cells of the
7094  * (*i*+1)-th mesh within the result mesh.
7095  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7096  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7097  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7098  *          is no more needed.
7099  *  \throw If \a a.size() == 0.
7100  *  \throw If \a a[ *i* ] == NULL.
7101  *  \throw If the meshes do not share the node coordinates array.
7102  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7103  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7104  */
7105 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7106 {
7107   if(meshes.empty())
7108     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7109   for(std::size_t ii=0;ii<meshes.size();ii++)
7110     if(!meshes[ii])
7111       {
7112         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7113         throw INTERP_KERNEL::Exception(oss.str());
7114       }
7115   const DataArrayDouble *coords=meshes.front()->getCoords();
7116   int meshDim=meshes.front()->getMeshDimension();
7117   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7118   mcIdType meshLgth=0;
7119   mcIdType meshIndexLgth=0;
7120   for(;iter!=meshes.end();iter++)
7121     {
7122       if(coords!=(*iter)->getCoords())
7123         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7124       if(meshDim!=(*iter)->getMeshDimension())
7125         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7126       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7127       meshIndexLgth+=(*iter)->getNumberOfCells();
7128     }
7129   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7130   nodal->alloc(meshLgth,1);
7131   mcIdType *nodalPtr=nodal->getPointer();
7132   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7133   nodalIndex->alloc(meshIndexLgth+1,1);
7134   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7135   mcIdType offset=0;
7136   for(iter=meshes.begin();iter!=meshes.end();iter++)
7137     {
7138       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7139       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7140       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7141       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7142       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7143       if(iter!=meshes.begin())
7144         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7145       else
7146         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7147       offset+=meshLgth2;
7148     }
7149   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7150   ret->setName("merge");
7151   ret->setMeshDimension(meshDim);
7152   ret->setConnectivity(nodal,nodalIndex,true);
7153   ret->setCoords(coords);
7154   return ret;
7155 }
7156
7157 /*!
7158  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7159  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7160  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7161  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7162  * New" mode are returned for each input mesh.
7163  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7164  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7165  *          valid values [0,1,2], see zipConnectivityTraducer().
7166  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7167  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7168  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7169  *          no more needed.
7170  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7171  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7172  *          is no more needed.
7173  *  \throw If \a meshes.size() == 0.
7174  *  \throw If \a meshes[ *i* ] == NULL.
7175  *  \throw If the meshes do not share the node coordinates array.
7176  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7177  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7178  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7179  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7180  */
7181 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7182 {
7183   //All checks are delegated to MergeUMeshesOnSameCoords
7184   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7185   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7186   corr.resize(meshes.size());
7187   std::size_t nbOfMeshes=meshes.size();
7188   mcIdType offset=0;
7189   const mcIdType *o2nPtr=o2n->begin();
7190   for(std::size_t i=0;i<nbOfMeshes;i++)
7191     {
7192       DataArrayIdType *tmp=DataArrayIdType::New();
7193       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7194       tmp->alloc(curNbOfCells,1);
7195       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7196       offset+=curNbOfCells;
7197       tmp->setName(meshes[i]->getName());
7198       corr[i]=tmp;
7199     }
7200   return ret.retn();
7201 }
7202
7203 /*!
7204  * Makes all given meshes share the nodal connectivity array. The common connectivity
7205  * array is created by concatenating the connectivity arrays of all given meshes. All
7206  * the given meshes must be of the same space dimension but dimension of cells **can
7207  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7208  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7209  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7210  *  \param [in,out] meshes - a vector of meshes to update.
7211  *  \throw If any of \a meshes is NULL.
7212  *  \throw If the coordinates array is not set in any of \a meshes.
7213  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7214  *  \throw If \a meshes are of different space dimension.
7215  */
7216 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7217 {
7218   std::size_t sz=meshes.size();
7219   if(sz==0 || sz==1)
7220     return;
7221   std::vector< const DataArrayDouble * > coords(meshes.size());
7222   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7223   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7224     {
7225       if((*it))
7226         {
7227           (*it)->checkConnectivityFullyDefined();
7228           const DataArrayDouble *coo=(*it)->getCoords();
7229           if(coo)
7230             *it2=coo;
7231           else
7232             {
7233               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7234               oss << " has no coordinate array defined !";
7235               throw INTERP_KERNEL::Exception(oss.str());
7236             }
7237         }
7238       else
7239         {
7240           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7241           oss << " is null !";
7242           throw INTERP_KERNEL::Exception(oss.str());
7243         }
7244     }
7245   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7246   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7247   mcIdType offset=(*it)->getNumberOfNodes();
7248   (*it++)->setCoords(res);
7249   for(;it!=meshes.end();it++)
7250     {
7251       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7252       (*it)->setCoords(res);
7253       (*it)->shiftNodeNumbersInConn(offset);
7254       offset+=oldNumberOfNodes;
7255     }
7256 }
7257
7258 /*!
7259  * Merges nodes coincident with a given precision within all given meshes that share
7260  * the nodal connectivity array. The given meshes **can be of different** mesh
7261  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7262  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7263  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7264  *  \param [in,out] meshes - a vector of meshes to update.
7265  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7266  *  \throw If any of \a meshes is NULL.
7267  *  \throw If the \a meshes do not share the same node coordinates array.
7268  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7269  */
7270 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7271 {
7272   if(meshes.empty())
7273     return ;
7274   std::set<const DataArrayDouble *> s;
7275   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7276     {
7277       if(*it)
7278         s.insert((*it)->getCoords());
7279       else
7280         {
7281           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 !";
7282           throw INTERP_KERNEL::Exception(oss.str());
7283         }
7284     }
7285   if(s.size()!=1)
7286     {
7287       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 !";
7288       throw INTERP_KERNEL::Exception(oss.str());
7289     }
7290   const DataArrayDouble *coo=*(s.begin());
7291   if(!coo)
7292     return;
7293   //
7294   DataArrayIdType *comm,*commI;
7295   coo->findCommonTuples(eps,-1,comm,commI);
7296   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7297   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7298   mcIdType newNbOfNodes;
7299   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7300   if(oldNbOfNodes==newNbOfNodes)
7301     return ;
7302   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7303   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7304     {
7305       (*it)->renumberNodesInConn(o2n->begin());
7306       (*it)->setCoords(newCoords);
7307     }
7308 }
7309
7310
7311 /*!
7312  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7313  */
7314 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7315 {
7316   std::size_t i, ip1;
7317   double v[3]={0.,0.,0.};
7318   std::size_t sz=std::distance(begin,end);
7319   if(!isQuadratic)
7320     for(i=0;i<sz;i++)
7321       {
7322         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7323         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7324         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];
7325         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7326         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7327       }
7328   else
7329     {
7330       // Same algorithm as above but also using intermediate quadratic points.
7331       // (taking only linear points might lead to issues if the linearized version of the
7332       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7333       std::size_t hsz = sz/2;
7334       for(std::size_t j=0;j<sz;j++)
7335         {
7336           if (j%2)  // current point i is quadratic, next point i+1 is standard
7337             {
7338               i = hsz+(j-1)/2;
7339               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7340             }
7341           else      // current point i is standard, next point i+1 is quadratic
7342             {
7343               i = j/2;
7344               ip1 = j/2+hsz;
7345             }
7346           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7347           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7348           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7349         }
7350     }
7351   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7352   return (ret>0.);
7353 }
7354
7355 /*!
7356  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7357  */
7358 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7359 {
7360   std::vector<std::pair<mcIdType,mcIdType> > edges;
7361   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7362   const mcIdType *bgFace=begin;
7363   for(std::size_t i=0;i<nbOfFaces;i++)
7364     {
7365       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7366       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7367       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7368         {
7369           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7370           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7371             return false;
7372           edges.push_back(p1);
7373         }
7374       bgFace=endFace+1;
7375     }
7376   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7377 }
7378
7379 /*!
7380  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7381  */
7382 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7383 {
7384   double vec0[3],vec1[3];
7385   std::size_t sz=std::distance(begin,end);
7386   if(sz%2!=0)
7387     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7388   mcIdType nbOfNodes=ToIdType(sz/2);
7389   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7390   const double *pt0=coords+3*begin[0];
7391   const double *pt1=coords+3*begin[nbOfNodes];
7392   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7393   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7394 }
7395
7396 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7397 {
7398   std::size_t sz=std::distance(begin,end);
7399   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7400   std::size_t nbOfNodes(sz/2);
7401   std::copy(begin,end,(mcIdType *)tmp);
7402   for(std::size_t j=1;j<nbOfNodes;j++)
7403     {
7404       begin[j]=tmp[nbOfNodes-j];
7405       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7406     }
7407 }
7408
7409 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7410 {
7411   std::size_t sz=std::distance(begin,end);
7412   if(sz!=4)
7413     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7414   double vec0[3],vec1[3];
7415   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7416   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];
7417   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;
7418 }
7419
7420 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7421 {
7422   std::size_t sz=std::distance(begin,end);
7423   if(sz!=5)
7424     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7425   double vec0[3];
7426   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7427   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7428   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7429 }
7430
7431 /*!
7432  * 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 )
7433  * 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
7434  * a 2D space.
7435  *
7436  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7437  * \param [in] coords the coordinates with nb of components exactly equal to 3
7438  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7439  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7440  */
7441 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7442                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7443 {
7444   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7445   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7446   double *vPtr=v->getPointer();
7447   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7448   double *pPtr=p->getPointer();
7449   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7450   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7451   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7452     {
7453       mcIdType face = e_f[e_fi[index] + i];
7454       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7455       // to differentiate faces going to different cells:
7456       pPtr++, *pPtr = 0;
7457       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7458         *pPtr += FromIdType<double>(f_e[j]);
7459     }
7460   pPtr=p->getPointer(); vPtr=v->getPointer();
7461   DataArrayIdType *comm1=0,*commI1=0;
7462   v->findCommonTuples(eps,-1,comm1,commI1);
7463   for (mcIdType i = 0; i < nbFaces; i++)
7464     if (comm1->findIdFirstEqual(i) < 0)
7465       {
7466         comm1->pushBackSilent(i);
7467         commI1->pushBackSilent(comm1->getNumberOfTuples());
7468       }
7469   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7470   const mcIdType *comm1Ptr=comm1->begin();
7471   const mcIdType *commI1Ptr=commI1->begin();
7472   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7473   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7474   //
7475   for(mcIdType i=0;i<nbOfGrps1;i++)
7476     {
7477       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7478       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7479       DataArrayIdType *comm2=0,*commI2=0;
7480       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7481       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7482         if (comm2->findIdFirstEqual(j) < 0)
7483           {
7484             comm2->pushBackSilent(j);
7485             commI2->pushBackSilent(comm2->getNumberOfTuples());
7486           }
7487       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7488       const mcIdType *comm2Ptr=comm2->begin();
7489       const mcIdType *commI2Ptr=commI2->begin();
7490       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7491       for(mcIdType j=0;j<nbOfGrps2;j++)
7492         {
7493           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7494             {
7495               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7496               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7497               res->pushBackSilent(-1);
7498             }
7499           else
7500             {
7501               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7502               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7503               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7504               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7505               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7506               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7507               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7508               const mcIdType *idsNodePtr=idsNode->begin();
7509               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];
7510               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7511               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7512               if(std::abs(norm)>eps)
7513                 {
7514                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7515                   mm3->rotate(center,vec,angle);
7516                 }
7517               mm3->changeSpaceDimension(2);
7518               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7519               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7520               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7521               mcIdType nbOfCells=mm4->getNumberOfCells();
7522               for(mcIdType k=0;k<nbOfCells;k++)
7523                 {
7524                   int l=0;
7525                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7526                     res->pushBackSilent(idsNodePtr[*work]);
7527                   res->pushBackSilent(-1);
7528                 }
7529             }
7530         }
7531     }
7532   res->popBackSilent();
7533 }
7534
7535 /*!
7536  * 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
7537  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7538  *
7539  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7540  * \param [in] coords coordinates expected to have 3 components.
7541  * \param [in] begin start of the nodal connectivity of the face.
7542  * \param [in] end end of the nodal connectivity (excluded) of the face.
7543  * \param [out] v the normalized vector of size 3
7544  * \param [out] p the pos of plane
7545  */
7546 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7547 {
7548   std::size_t nbPoints=std::distance(begin,end);
7549   if(nbPoints<3)
7550     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7551   double vec[3]={0.,0.,0.};
7552   std::size_t j=0;
7553   bool refFound=false;
7554   for(;j<nbPoints-1 && !refFound;j++)
7555     {
7556       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7557       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7558       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7559       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7560       if(norm>eps)
7561         {
7562           refFound=true;
7563           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7564         }
7565     }
7566   for(std::size_t i=j;i<nbPoints-1;i++)
7567     {
7568       double curVec[3];
7569       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7570       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7571       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7572       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7573       if(norm<eps)
7574         continue;
7575       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7576       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];
7577       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7578       if(norm>eps)
7579         {
7580           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7581           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7582           return ;
7583         }
7584     }
7585   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7586 }
7587
7588 /*!
7589  * This method tries to obtain a well oriented polyhedron.
7590  * If the algorithm fails, an exception will be thrown.
7591  */
7592 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7593 {
7594   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7595   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7596   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7597   isPerm[0]=true;
7598   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7599   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7600   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7601   //
7602   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7603     {
7604       bgFace=begin;
7605       std::size_t smthChanged=0;
7606       for(std::size_t i=0;i<nbOfFaces;i++)
7607         {
7608           endFace=std::find(bgFace+1,end,-1);
7609           nbOfEdgesInFace=std::distance(bgFace,endFace);
7610           if(!isPerm[i])
7611             {
7612               bool b=false;
7613               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7614                 {
7615                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7616                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7617                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7618                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7619                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7620                 }
7621               if(isPerm[i])
7622                 {
7623                   if(!b)
7624                     std::reverse(bgFace+1,endFace);
7625                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7626                     {
7627                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7628                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7629                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7630                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7631                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7632                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7633                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7634                       if(it!=edgesOK.end())
7635                         {
7636                           edgesOK.erase(it);
7637                           edgesFinished.push_back(p1);
7638                         }
7639                       else
7640                         edgesOK.push_back(p1);
7641                     }
7642                 }
7643             }
7644           bgFace=endFace+1;
7645         }
7646       if(smthChanged==0)
7647         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7648     }
7649   if(!edgesOK.empty())
7650     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7651   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7652     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7653       bgFace=begin;
7654       for(std::size_t i=0;i<nbOfFaces;i++)
7655         {
7656           endFace=std::find(bgFace+1,end,-1);
7657           std::reverse(bgFace+1,endFace);
7658           bgFace=endFace+1;
7659         }
7660     }
7661 }
7662
7663
7664 /*!
7665  * This method makes the assumption spacedimension == meshdimension == 2.
7666  * This method works only for linear cells.
7667  *
7668  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7669  */
7670 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7671 {
7672   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7673     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7674   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7675   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7676   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7677   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7678   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7679   mcIdType nbCells=skin->getNumberOfCells();
7680   if(nbCells==nbOfNodesExpected)
7681     return buildUnionOf2DMeshLinear(skin,n2o);
7682   else if(2*nbCells==nbOfNodesExpected)
7683     return buildUnionOf2DMeshQuadratic(skin,n2o);
7684   else
7685     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7686 }
7687
7688 /*!
7689  * This method makes the assumption spacedimension == meshdimension == 3.
7690  * This method works only for linear cells.
7691  *
7692  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7693  */
7694 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7695 {
7696   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7697     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7698   MCAuto<MEDCouplingUMesh> m=computeSkin();
7699   const mcIdType *conn=m->getNodalConnectivity()->begin();
7700   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7701   mcIdType nbOfCells=m->getNumberOfCells();
7702   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7703   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7704   if(nbOfCells<1)
7705     return ret.retn();
7706   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7707   for(mcIdType i=1;i<nbOfCells;i++)
7708     {
7709       *work++=-1;
7710       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7711     }
7712   return ret.retn();
7713 }
7714
7715 /*!
7716  * \brief Creates a graph of cell neighbors
7717  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7718  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7719  *  For example
7720  *  - index:  0 3 5 6 6
7721  *  - value:  1 2 3 2 3 3
7722  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7723  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7724  */
7725 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7726 {
7727   checkConnectivityFullyDefined();
7728
7729   int meshDim = this->getMeshDimension();
7730   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7731   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7732   this->getReverseNodalConnectivity(revConn,indexr);
7733   const mcIdType* indexr_ptr=indexr->begin();
7734   const mcIdType* revConn_ptr=revConn->begin();
7735
7736   const MEDCoupling::DataArrayIdType* index;
7737   const MEDCoupling::DataArrayIdType* conn;
7738   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7739   index=this->getNodalConnectivityIndex();
7740   mcIdType nbCells=this->getNumberOfCells();
7741   const mcIdType* index_ptr=index->begin();
7742   const mcIdType* conn_ptr=conn->begin();
7743
7744   //creating graph arcs (cell to cell relations)
7745   //arcs are stored in terms of (index,value) notation
7746   // 0 3 5 6 6
7747   // 1 2 3 2 3 3
7748   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7749   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7750
7751   //warning here one node have less than or equal effective number of cell with it
7752   //but cell could have more than effective nodes
7753   //because other equals nodes in other domain (with other global inode)
7754   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7755   std::vector <mcIdType> cell2cell;
7756   cell2cell.reserve(3*nbCells);
7757
7758   for (mcIdType icell=0; icell<nbCells;icell++)
7759     {
7760       std::map<mcIdType,mcIdType > counter;
7761       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7762         {
7763           mcIdType inode=conn_ptr[iconn];
7764           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7765             {
7766               mcIdType icell2=revConn_ptr[iconnr];
7767               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7768               if (iter!=counter.end()) (iter->second)++;
7769               else counter.insert(std::make_pair(icell2,1));
7770             }
7771         }
7772       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7773            iter!=counter.end(); iter++)
7774         if (iter->second >= meshDim)
7775           {
7776             cell2cell_index[icell+1]++;
7777             cell2cell.push_back(iter->first);
7778           }
7779     }
7780   indexr->decrRef();
7781   revConn->decrRef();
7782   cell2cell_index[0]=0;
7783   for (mcIdType icell=0; icell<nbCells;icell++)
7784     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7785
7786   //filling up index and value to create skylinearray structure
7787   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7788   return array;
7789 }
7790
7791
7792 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7793 {
7794   mcIdType nbOfCells=getNumberOfCells();
7795   if(nbOfCells<=0)
7796     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7797   ofs << "  <" << getVTKDataSetType() << ">\n";
7798   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7799   ofs << "      <PointData>\n" << pointData << std::endl;
7800   ofs << "      </PointData>\n";
7801   ofs << "      <CellData>\n" << cellData << std::endl;
7802   ofs << "      </CellData>\n";
7803   ofs << "      <Points>\n";
7804   if(getSpaceDimension()==3)
7805     _coords->writeVTK(ofs,8,"Points",byteData);
7806   else
7807     {
7808       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7809       coo->writeVTK(ofs,8,"Points",byteData);
7810     }
7811   ofs << "      </Points>\n";
7812   ofs << "      <Cells>\n";
7813   const mcIdType *cPtr=_nodal_connec->begin();
7814   const mcIdType *cIPtr=_nodal_connec_index->begin();
7815   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7816   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7817   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7818   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7819   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7820   mcIdType szFaceOffsets=0,szConn=0;
7821   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7822     {
7823       *w2=cPtr[cIPtr[i]];
7824       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7825         {
7826           *w1=-1;
7827           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7828           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7829         }
7830       else
7831         {
7832           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7833           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7834           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7835           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7836           w4=std::copy(c.begin(),c.end(),w4);
7837         }
7838     }
7839   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7840   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7841     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7842   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7843   types->writeVTK(ofs,8,"UInt8","types",byteData);
7844   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7845   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7846   if(szFaceOffsets!=0)
7847     {//presence of Polyhedra
7848       connectivity->reAlloc(szConn);
7849       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7850       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7851       w1=faces->getPointer();
7852       for(mcIdType i=0;i<nbOfCells;i++)
7853         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7854           {
7855             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7856             *w1++=nbFaces;
7857             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7858             for(mcIdType j=0;j<nbFaces;j++)
7859               {
7860                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7861                 *w1++=ToIdType(std::distance(w6,w5));
7862                 w1=std::copy(w6,w5,w1);
7863                 w6=w5+1;
7864               }
7865           }
7866       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7867     }
7868   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7869   ofs << "      </Cells>\n";
7870   ofs << "    </Piece>\n";
7871   ofs << "  </" << getVTKDataSetType() << ">\n";
7872 }
7873
7874 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7875 {
7876   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7877   if(_mesh_dim==-2)
7878     { stream << " Not set !"; return ; }
7879   stream << " Mesh dimension : " << _mesh_dim << ".";
7880   if(_mesh_dim==-1)
7881     return ;
7882   if(!_coords)
7883     { stream << " No coordinates set !"; return ; }
7884   if(!_coords->isAllocated())
7885     { stream << " Coordinates set but not allocated !"; return ; }
7886   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7887   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7888   if(!_nodal_connec_index)
7889     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7890   if(!_nodal_connec_index->isAllocated())
7891     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7892   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7893   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7894   if(cpt!=1 || lgth<1)
7895     return ;
7896   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7897 }
7898
7899 std::string MEDCouplingUMesh::getVTKDataSetType() const
7900 {
7901   return std::string("UnstructuredGrid");
7902 }
7903
7904 std::string MEDCouplingUMesh::getVTKFileExtension() const
7905 {
7906   return std::string("vtu");
7907 }
7908
7909
7910
7911 /**
7912  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7913  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7914  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7915  * The caller is to deal with the resulting DataArrayIdType.
7916  *  \throw If the coordinate array is not set.
7917  *  \throw If the nodal connectivity of the cells is not defined.
7918  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7919  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7920  *
7921  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7922  */
7923 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7924 {
7925   checkFullyDefined();
7926   if(getMeshDimension()!=1)
7927     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7928
7929   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7930   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7931   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7932   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7933   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7934   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7935   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7936   const mcIdType * dsi(_dsi->begin());
7937   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7938   m_points=0;
7939   if (dsii->getNumberOfTuples())
7940     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7941
7942   mcIdType nc=getNumberOfCells();
7943   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7944   result->alloc(nc,1);
7945
7946   // set of edges not used so far
7947   std::set<mcIdType> edgeSet;
7948   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7949
7950   mcIdType startSeg=0;
7951   mcIdType newIdx=0;
7952   // while we have points with only one neighbor segments
7953   do
7954     {
7955       std::list<mcIdType> linePiece;
7956       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7957       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7958         {
7959           // Fill the list forward (resp. backward) from the start segment:
7960           mcIdType activeSeg = startSeg;
7961           mcIdType prevPointId = -20;
7962           mcIdType ptId;
7963           while (!edgeSet.empty())
7964             {
7965               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7966                 {
7967                   if (direction==0)
7968                     linePiece.push_back(activeSeg);
7969                   else
7970                     linePiece.push_front(activeSeg);
7971                   edgeSet.erase(activeSeg);
7972                 }
7973
7974               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7975               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7976               if (dsi[ptId] == 1) // hitting the end of the line
7977                 break;
7978               prevPointId = ptId;
7979               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7980               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7981             }
7982         }
7983       // Done, save final piece into DA:
7984       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7985       newIdx += ToIdType(linePiece.size());
7986
7987       // identify next valid start segment (one which is not consumed)
7988       if(!edgeSet.empty())
7989         startSeg = *(edgeSet.begin());
7990     }
7991   while (!edgeSet.empty());
7992   return result.retn();
7993 }
7994
7995 /**
7996  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7997  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7998  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7999  * a minimal creation of new nodes is wanted.
8000  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
8001  * nodes if a SEG3 is split without information of middle.
8002  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
8003  * avoid to have a non conform mesh.
8004  *
8005  * \return mcIdType - the number of new nodes created (in most of cases 0).
8006  *
8007  * \throw If \a this is not coherent.
8008  * \throw If \a this has not spaceDim equal to 2.
8009  * \throw If \a this has not meshDim equal to 2.
8010  * \throw If some subcells needed to be split are orphan.
8011  * \sa MEDCouplingUMesh::conformize2D
8012  */
8013 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
8014 {
8015   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
8016     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
8017   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
8018   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
8019     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
8020   if(midOpt==0 && midOptI==0)
8021     {
8022       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
8023       return 0;
8024     }
8025   else if(midOpt!=0 && midOptI!=0)
8026     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
8027   else
8028     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
8029 }
8030
8031 /*!
8032  * 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
8033  * 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
8034  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
8035  * 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
8036  * 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.
8037  *
8038  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
8039  */
8040 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
8041 {
8042   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
8043   if(sz>=4)
8044     {
8045       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
8046       if(cm.getDimension()==2)
8047         {
8048           const mcIdType *node=nodalConnBg+1;
8049           mcIdType startNode=*node++;
8050           double refX=coords[2*startNode];
8051           for(;node!=nodalConnEnd;node++)
8052             {
8053               if(coords[2*(*node)]<refX)
8054                 {
8055                   startNode=*node;
8056                   refX=coords[2*startNode];
8057                 }
8058             }
8059           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
8060           refX=1e300;
8061           double tmp1;
8062           double tmp2[2];
8063           double angle0=-M_PI/2;
8064           //
8065           mcIdType nextNode=-1;
8066           mcIdType prevNode=-1;
8067           double resRef;
8068           double angleNext=0.;
8069           while(nextNode!=startNode)
8070             {
8071               nextNode=-1;
8072               resRef=1e300;
8073               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
8074                 {
8075                   if(*node!=tmpOut.back() && *node!=prevNode)
8076                     {
8077                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
8078                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
8079                       double res;
8080                       if(angleM<=angle0)
8081                         res=angle0-angleM;
8082                       else
8083                         res=angle0-angleM+2.*M_PI;
8084                       if(res<resRef)
8085                         {
8086                           nextNode=*node;
8087                           resRef=res;
8088                           angleNext=angleM;
8089                         }
8090                     }
8091                 }
8092               if(nextNode!=startNode)
8093                 {
8094                   angle0=angleNext-M_PI;
8095                   if(angle0<-M_PI)
8096                     angle0+=2*M_PI;
8097                   prevNode=tmpOut.back();
8098                   tmpOut.push_back(nextNode);
8099                 }
8100             }
8101           std::vector<mcIdType> tmp3(2*(sz-1));
8102           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8103           std::copy(nodalConnBg+1,nodalConnEnd,it);
8104           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8105             {
8106               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8107               return false;
8108             }
8109           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8110             {
8111               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8112               return false;
8113             }
8114           else
8115             {
8116               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8117               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8118               return true;
8119             }
8120         }
8121       else
8122         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8123     }
8124   else
8125     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8126 }
8127
8128 /*!
8129  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8130  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8131  * 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]].
8132  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8133  * A negative value in \b arrIn means that it is ignored.
8134  * 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.
8135  *
8136  * \param [in] arrIn arr origin array from which the extraction will be done.
8137  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8138  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8139  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8140  */
8141 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8142 {
8143   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8144   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8145 }
8146
8147 /*!
8148  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8149  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8150  * 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]].
8151  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8152  * A negative value in \b arrIn means that it is ignored.
8153  * 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.
8154  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8155  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8156  * \param [in] arrIn arr origin array from which the extraction will be done.
8157  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8158  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8159  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8160  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8161  * \sa MEDCouplingUMesh::partitionBySpreadZone
8162  */
8163 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8164 {
8165   nbOfDepthPeelingPerformed=0;
8166   if(!arrIndxIn)
8167     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8168   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8169   if(nbOfTuples<=0)
8170     {
8171       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8172       return ret;
8173     }
8174   //
8175   std::vector<bool> fetched(nbOfTuples,false);
8176   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8177 }
8178
8179
8180
8181 /*!
8182  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8183  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8184  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8185  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8186  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8187  *
8188  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8189  */
8190 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8191 {
8192   checkFullyDefined();
8193   int mdim=getMeshDimension();
8194   int spaceDim=getSpaceDimension();
8195   if(mdim!=spaceDim)
8196     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8197   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8198   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8199   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8200   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8201   ret->setCoords(getCoords());
8202   ret->allocateCells(ToIdType(partition.size()));
8203   //
8204   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8205     {
8206       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8207       MCAuto<DataArrayIdType> cell;
8208       switch(mdim)
8209       {
8210         case 2:
8211           cell=tmp->buildUnionOf2DMesh();
8212           break;
8213         case 3:
8214           cell=tmp->buildUnionOf3DMesh();
8215           break;
8216         default:
8217           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8218       }
8219
8220       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8221     }
8222   //
8223   ret->finishInsertingCells();
8224   return ret.retn();
8225 }
8226
8227 /*!
8228  * This method partitions \b this into contiguous zone.
8229  * This method only needs a well defined connectivity. Coordinates are not considered here.
8230  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8231  */
8232 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8233 {
8234   DataArrayIdType *neigh=0,*neighI=0;
8235   computeNeighborsOfCells(neigh,neighI);
8236   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8237   return PartitionBySpreadZone(neighAuto,neighIAuto);
8238 }
8239
8240 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8241 {
8242   if(!arrIn || !arrIndxIn)
8243     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8244   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8245   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8246   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8247     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8248   mcIdType nbOfCellsCur(nbOfTuples-1);
8249   std::vector<DataArrayIdType *> ret;
8250   if(nbOfCellsCur<=0)
8251     return ret;
8252   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8253   std::vector< MCAuto<DataArrayIdType> > ret2;
8254   mcIdType seed=0;
8255   while(seed<nbOfCellsCur)
8256     {
8257       mcIdType nbOfPeelPerformed=0;
8258       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8259       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8260     }
8261   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8262     ret.push_back((*it).retn());
8263   return ret;
8264 }
8265
8266 /*!
8267  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8268  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8269  *
8270  * \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.
8271  * \return a newly allocated DataArrayIdType to be managed by the caller.
8272  * \throw In case of \a code has not the right format (typically of size 3*n)
8273  */
8274 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8275 {
8276   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8277   std::size_t nb=code.size()/3;
8278   if(code.size()%3!=0)
8279     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8280   ret->alloc(nb,2);
8281   mcIdType *retPtr=ret->getPointer();
8282   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8283     {
8284       retPtr[0]=code[3*i+2];
8285       retPtr[1]=code[3*i+2]+code[3*i+1];
8286     }
8287   return ret.retn();
8288 }
8289
8290 /*!
8291  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8292  * All cells in \a this are expected to be linear 3D cells.
8293  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8294  * It leads to an increase to number of cells.
8295  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8296  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8297  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8298  *
8299  * \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.
8300  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8301  * \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.
8302  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8303  *          an id of old cell producing it. The caller is to delete this array using
8304  *         decrRef() as it is no more needed.
8305  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8306  *
8307  * \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
8308  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8309  *
8310  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8311  * \throw If \a this is not fully constituted with linear 3D cells.
8312  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8313  */
8314 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8315 {
8316   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8317   checkConnectivityFullyDefined();
8318   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8319     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8320   mcIdType nbOfCells=getNumberOfCells();
8321   mcIdType nbNodes(getNumberOfNodes());
8322   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8323   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8324   mcIdType *retPt(ret->getPointer());
8325   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8326   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8327   const mcIdType *oldc(_nodal_connec->begin());
8328   const mcIdType *oldci(_nodal_connec_index->begin());
8329   const double *coords(_coords->begin());
8330   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8331     {
8332       std::vector<mcIdType> a; std::vector<double> b;
8333       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8334       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8335       const mcIdType *aa(&a[0]);
8336       if(!b.empty())
8337         {
8338           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8339             if(*it<0)
8340               *it=(-(*(it))-1+nbNodes);
8341           addPts->insertAtTheEnd(b.begin(),b.end());
8342           nbNodes+=ToIdType(b.size()/3);
8343         }
8344       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8345         newConn->insertAtTheEnd(aa,aa+4);
8346     }
8347   if(!addPts->empty())
8348     {
8349       addPts->rearrange(3);
8350       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8351       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8352       ret0->setCoords(addPts);
8353     }
8354   else
8355     {
8356       nbOfAdditionalPoints=0;
8357       ret0->setCoords(getCoords());
8358     }
8359   ret0->setNodalConnectivity(newConn);
8360   //
8361   ret->computeOffsetsFull();
8362   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8363   return ret0.retn();
8364 }
8365
8366 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8367     _own_cell(true),_cell_id(-1),_nb_cell(0)
8368 {
8369   if(mesh)
8370     {
8371       mesh->incrRef();
8372       _nb_cell=mesh->getNumberOfCells();
8373     }
8374 }
8375
8376 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8377 {
8378   if(_mesh)
8379     _mesh->decrRef();
8380   if(_own_cell)
8381     delete _cell;
8382 }
8383
8384 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8385     _own_cell(false),_cell_id(bg-1),
8386     _nb_cell(end)
8387 {
8388   if(mesh)
8389     mesh->incrRef();
8390 }
8391
8392 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8393 {
8394   _cell_id++;
8395   if(_cell_id<_nb_cell)
8396     {
8397       _cell->next();
8398       return _cell;
8399     }
8400   else
8401     return 0;
8402 }
8403
8404 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8405 {
8406   if(_mesh)
8407     _mesh->incrRef();
8408 }
8409
8410 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8411 {
8412   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8413 }
8414
8415 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8416 {
8417   if(_mesh)
8418     _mesh->decrRef();
8419 }
8420
8421 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8422     _itc(itc),
8423     _bg(bg),_end(end)
8424 {
8425   if(_mesh)
8426     _mesh->incrRef();
8427 }
8428
8429 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8430 {
8431   if(_mesh)
8432     _mesh->decrRef();
8433 }
8434
8435 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8436 {
8437   return _type;
8438 }
8439
8440 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8441 {
8442   return _end-_bg;
8443 }
8444
8445 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8446 {
8447   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8448 }
8449
8450 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8451 {
8452   if(mesh)
8453     {
8454       mesh->incrRef();
8455       _nb_cell=mesh->getNumberOfCells();
8456     }
8457 }
8458
8459 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8460 {
8461   if(_mesh)
8462     _mesh->decrRef();
8463   delete _cell;
8464 }
8465
8466 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8467 {
8468   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8469   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8470   if(_cell_id<_nb_cell)
8471     {
8472       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8473       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8474       mcIdType startId=_cell_id;
8475       _cell_id+=nbOfElems;
8476       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8477     }
8478   else
8479     return 0;
8480 }
8481
8482 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8483 {
8484   if(mesh)
8485     {
8486       _conn=mesh->getNodalConnectivity()->getPointer();
8487       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8488     }
8489 }
8490
8491 void MEDCouplingUMeshCell::next()
8492 {
8493   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8494     {
8495       _conn+=_conn_lgth;
8496       _conn_indx++;
8497     }
8498   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8499 }
8500
8501 std::string MEDCouplingUMeshCell::repr() const
8502 {
8503   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8504     {
8505       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8506       oss << " : ";
8507       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8508       return oss.str();
8509     }
8510   else
8511     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8512 }
8513
8514 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8515 {
8516   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8517     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8518   else
8519     return INTERP_KERNEL::NORM_ERROR;
8520 }
8521
8522 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8523 {
8524   lgth=_conn_lgth;
8525   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8526     return _conn;
8527   else
8528     return 0;
8529 }