Salome HOME
ef1d2381ce3cd6e6efdb1758fc64fdabb424bc83
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is informatically clean, most probably is writable, exchangeable and available for all
212  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
213  * method thoroughly checks the nodal connectivity. For more geometrical checking
214  * checkGeomConsistency method is better than this.
215  * 
216  * \sa MEDCouplingUMesh::checkGeomConsistency
217  * 
218  *  \param [in] eps - a not used parameter.
219  *  \throw If the mesh dimension is not set.
220  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
221  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
222  *  \throw If the connectivity data array has more than one component.
223  *  \throw If the connectivity data array has a named component.
224  *  \throw If the connectivity index data array has more than one component.
225  *  \throw If the connectivity index data array has a named component.
226  *  \throw If number of nodes defining an element does not correspond to the type of element.
227  *  \throw If the nodal connectivity includes an invalid node id.
228  */
229 void MEDCouplingUMesh::checkConsistency(double eps) const
230 {
231   checkConsistencyLight();
232   if(_mesh_dim==-1)
233     return ;
234   int meshDim=getMeshDimension();
235   mcIdType nbOfNodes=getNumberOfNodes();
236   mcIdType nbOfCells=getNumberOfCells();
237   const mcIdType *ptr=_nodal_connec->getConstPointer();
238   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
239   for(mcIdType i=0;i<nbOfCells;i++)
240     {
241       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
242       if(ToIdType(cm.getDimension())!=meshDim)
243         {
244           std::ostringstream oss;
245           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
246           throw INTERP_KERNEL::Exception(oss.str());
247         }
248       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
249       if(!cm.isDynamic())
250         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
254             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
255             throw INTERP_KERNEL::Exception(oss.str());
256           }
257       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
258         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
259           {
260             std::ostringstream oss;
261             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
262             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
263             throw INTERP_KERNEL::Exception(oss.str());
264           }
265       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
266         {
267           mcIdType nodeId=*w;
268           if(nodeId>=0)
269             {
270               if(nodeId>=nbOfNodes)
271                 {
272                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
273                   throw INTERP_KERNEL::Exception(oss.str());
274                 }
275             }
276           else if(nodeId<-1)
277             {
278               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
279               throw INTERP_KERNEL::Exception(oss.str());
280             }
281           else
282             {
283               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
284                 {
285                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
286                   throw INTERP_KERNEL::Exception(oss.str());
287                 }
288             }
289         }
290     }
291 }
292
293 /*!
294  * This method adds some geometrical checks in addition to the informatical check of checkConsistency method.
295  * This method in particular checks that a same node is not repeated several times in a cell.
296  * 
297  *  \throw If there is a presence a multiple same node ID in nodal connectivity of cell.
298  */
299 void MEDCouplingUMesh::checkGeomConsistency(double eps) const
300 {
301   this->checkConsistency(eps);
302   auto nbOfCells(getNumberOfCells());
303   const mcIdType *ptr(_nodal_connec->begin()),*ptrI(_nodal_connec_index->begin());
304   for(auto icell = 0 ; icell < nbOfCells ; ++icell)
305   {
306     std::set<mcIdType> s(ptr+ptrI[icell]+1,ptr+ptrI[icell+1]);
307     if(ToIdType(s.size())==ptrI[icell+1]-ptrI[icell]-1)
308       continue;
309     std::ostringstream oss; oss << "MEDCouplingUMesh::checkGeomConsistency : for cell #" << icell << " presence of multiple same nodeID !";
310     throw INTERP_KERNEL::Exception(oss.str());
311   }
312 }
313
314
315 /*!
316  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
317  * elements contained in the mesh. For more info on the mesh dimension see
318  * \ref MEDCouplingUMeshPage.
319  *  \param [in] meshDim - a new mesh dimension.
320  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
321  */
322 void MEDCouplingUMesh::setMeshDimension(int meshDim)
323 {
324   if(meshDim<-1 || meshDim>3)
325     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
326   _mesh_dim=meshDim;
327   declareAsNew();
328 }
329
330 /*!
331  * Allocates memory to store an estimation of the given number of cells.
332  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
333  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
334  * If a nodal connectivity previously existed before the call of this method, it will be reset.
335  *
336  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
337  *
338  *  \if ENABLE_EXAMPLES
339  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
340  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
341  *  \endif
342  */
343 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
344 {
345   if(nbOfCells<0)
346     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
347   if(_nodal_connec_index)
348     {
349       _nodal_connec_index->decrRef();
350     }
351   if(_nodal_connec)
352     {
353       _nodal_connec->decrRef();
354     }
355   _nodal_connec_index=DataArrayIdType::New();
356   _nodal_connec_index->reserve(nbOfCells+1);
357   _nodal_connec_index->pushBackSilent(0);
358   _nodal_connec=DataArrayIdType::New();
359   _nodal_connec->reserve(2*nbOfCells);
360   _types.clear();
361   declareAsNew();
362 }
363
364 /*!
365  * Appends a cell to the connectivity array. For deeper understanding what is
366  * happening see \ref MEDCouplingUMeshNodalConnectivity.
367  *  \param [in] type - type of cell to add.
368  *  \param [in] size - number of nodes constituting this cell.
369  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
370  *
371  *  \if ENABLE_EXAMPLES
372  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
373  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
374  *  \endif
375  */
376 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
377 {
378   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
379   if(_nodal_connec_index==0)
380     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
381   if(ToIdType(cm.getDimension())==_mesh_dim)
382     {
383       if(!cm.isDynamic())
384         if(size!=ToIdType(cm.getNumberOfNodes()))
385           {
386             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
387             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
388             throw INTERP_KERNEL::Exception(oss.str());
389           }
390       mcIdType idx=_nodal_connec_index->back();
391       mcIdType val=idx+size+1;
392       _nodal_connec_index->pushBackSilent(val);
393       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
394       _types.insert(type);
395     }
396   else
397     {
398       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
399       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
400       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
401       throw INTERP_KERNEL::Exception(oss.str());
402     }
403 }
404
405 /*!
406  * Compacts data arrays to release unused memory. This method is to be called after
407  * finishing cell insertion using \a this->insertNextCell().
408  *
409  *  \if ENABLE_EXAMPLES
410  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
411  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
412  *  \endif
413  */
414 void MEDCouplingUMesh::finishInsertingCells()
415 {
416   _nodal_connec->pack();
417   _nodal_connec_index->pack();
418   _nodal_connec->declareAsNew();
419   _nodal_connec_index->declareAsNew();
420   updateTime();
421 }
422
423 /*!
424  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
425  * Useful for python users.
426  */
427 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
428 {
429   return new MEDCouplingUMeshCellIterator(this);
430 }
431
432 /*!
433  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
434  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
435  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
436  * Useful for python users.
437  */
438 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
439 {
440   if(!checkConsecutiveCellTypes())
441     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
442   return new MEDCouplingUMeshCellByTypeEntry(this);
443 }
444
445 /*!
446  * Returns a set of all cell types available in \a this mesh.
447  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
448  * \warning this method does not throw any exception even if \a this is not defined.
449  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
450  */
451 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
452 {
453   return _types;
454 }
455
456 /*!
457  * This method returns the sorted list of geometric types in \a this.
458  * Sorted means in the same order than the cells in \a this. A single entry in return vector means the maximal chunk of consecutive cells in \a this
459  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
460  *
461  * \throw if connectivity in \a this is not correctly defined.
462  *
463  * \sa MEDCouplingMesh::getAllGeoTypes
464  */
465 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
466 {
467   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
468   checkConnectivityFullyDefined();
469   mcIdType nbOfCells=getNumberOfCells();
470   if(nbOfCells==0)
471     return ret;
472   if(getNodalConnectivityArrayLen()<1)
473     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
474   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
475   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
476   for(mcIdType i=1;i<nbOfCells;i++,ci++)
477     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
478       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
479   return ret;
480 }
481
482 /*!
483  * This method is a method that compares \a this and \a other.
484  * This method compares \b all attributes, even names and component names.
485  */
486 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
487 {
488   if(!other)
489     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
490   std::ostringstream oss; oss.precision(15);
491   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
492   if(!otherC)
493     {
494       reason="mesh given in input is not castable in MEDCouplingUMesh !";
495       return false;
496     }
497   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
498     return false;
499   if(_mesh_dim!=otherC->_mesh_dim)
500     {
501       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
502       reason=oss.str();
503       return false;
504     }
505   if(_types!=otherC->_types)
506     {
507       oss << "umesh geometric type mismatch :\nThis geometric types are :";
508       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
509         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
510       oss << "\nOther geometric types are :";
511       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
512         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
513       reason=oss.str();
514       return false;
515     }
516   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
517     if(_nodal_connec==0 || otherC->_nodal_connec==0)
518       {
519         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
520         return false;
521       }
522   if(_nodal_connec!=otherC->_nodal_connec)
523     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
524       {
525         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
526         return false;
527       }
528   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
529     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
530       {
531         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
532         return false;
533       }
534   if(_nodal_connec_index!=otherC->_nodal_connec_index)
535     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
536       {
537         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
538         return false;
539       }
540   return true;
541 }
542
543 /*!
544  * Checks if data arrays of this mesh (node coordinates, nodal
545  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
546  * not considered.
547  *  \param [in] other - the mesh to compare with.
548  *  \param [in] prec - precision value used to compare node coordinates.
549  *  \return bool - \a true if the two meshes are same.
550  */
551 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
552 {
553   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
554   if(!otherC)
555     return false;
556   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
557     return false;
558   if(_mesh_dim!=otherC->_mesh_dim)
559     return false;
560   if(_types!=otherC->_types)
561     return false;
562   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
563     if(_nodal_connec==0 || otherC->_nodal_connec==0)
564       return false;
565   if(_nodal_connec!=otherC->_nodal_connec)
566     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
567       return false;
568   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
569     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
570       return false;
571   if(_nodal_connec_index!=otherC->_nodal_connec_index)
572     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
573       return false;
574   return true;
575 }
576
577 /*!
578  * Checks if \a this and \a other meshes are geometrically equivalent with high
579  * probability, else an exception is thrown. The meshes are considered equivalent if
580  * (1) meshes contain the same number of nodes and the same number of elements of the
581  * same types (2) three cells of the two meshes (first, last and middle) are based
582  * on coincident nodes (with a specified precision).
583  *  \param [in] other - the mesh to compare with.
584  *  \param [in] prec - the precision used to compare nodes of the two meshes.
585  *  \throw If the two meshes do not match.
586  */
587 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
588 {
589   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
590   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
591   if(!otherC)
592     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
593 }
594
595 /*!
596  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
597  * cells each node belongs to.
598  * \warning For speed reasons, this method does not check if node ids in the nodal
599  *          connectivity correspond to the size of node coordinates array.
600  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
601  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
602  *        dividing cell ids in \a revNodal into groups each referring to one
603  *        node. Its every element (except the last one) is an index pointing to the
604  *         first id of a group of cells. For example cells sharing the node #1 are
605  *        described by following range of indices:
606  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
607  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
608  *        Number of cells sharing the *i*-th node is
609  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
610  * \throw If the coordinates array is not set.
611  * \throw If the nodal connectivity of cells is not defined.
612  *
613  * \if ENABLE_EXAMPLES
614  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
615  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
616  * \endif
617  */
618 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
619 {
620   checkFullyDefined();
621   mcIdType nbOfNodes(getNumberOfNodes());
622   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
623   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
624   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
625   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
626   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
627   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
628     {
629       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
630       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
631         if(*iter>=0)//for polyhedrons
632           {
633             nbOfEltsInRevNodal++;
634             revNodalIndxPtr[(*iter)+1]++;
635           }
636     }
637   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
638   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
639   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
640   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
641   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
642     {
643       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
644       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
645       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
646         if(*iter>=0)//for polyhedrons
647           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind(std::equal_to<mcIdType>(),std::placeholders::_1,-1))=eltId;
648     }
649 }
650
651 /*!
652  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
653  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
654  * describing correspondence between cells of \a this and the result meshes are
655  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
656  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
657  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
658  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
659  * \warning For speed reasons, this method does not check if node ids in the nodal
660  *          connectivity correspond to the size of node coordinates array.
661  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
662  *          to write this mesh to the MED file, its cells must be sorted using
663  *          sortCellsInMEDFileFrmt().
664  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
665  *         each cell of \a this mesh.
666  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
667  *        dividing cell ids in \a desc into groups each referring to one
668  *        cell of \a this mesh. Its every element (except the last one) is an index
669  *        pointing to the first id of a group of cells. For example cells of the
670  *        result mesh bounding the cell #1 of \a this mesh are described by following
671  *        range of indices:
672  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
673  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
674  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
675  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
676  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
677  *         by each cell of the result mesh.
678  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
679  *        in the result mesh,
680  *        dividing cell ids in \a revDesc into groups each referring to one
681  *        cell of the result mesh the same way as \a descIndx divides \a desc.
682  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
683  *        delete this mesh using decrRef() as it is no more needed.
684  *  \throw If the coordinates array is not set.
685  *  \throw If the nodal connectivity of cells is node defined.
686  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
687  *         revDescIndx == NULL.
688  *
689  *  \if ENABLE_EXAMPLES
690  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
691  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
692  *  \endif
693  * \sa buildDescendingConnectivity2()
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
698 }
699
700 /*!
701  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
702  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
703  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
704  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
705  * \sa MEDCouplingUMesh::buildDescendingConnectivity
706  */
707 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
708 {
709   checkFullyDefined();
710   if(getMeshDimension()!=3)
711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
712   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
713 }
714
715 /*!
716  * This method computes the micro edges constituting each cell in \a this. Micro edge is an edge for non quadratic cells. Micro edge is an half edge for quadratic cells.
717  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
718  * 
719  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
720  */
721 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
722 {
723    checkFullyDefined();
724    switch(getMeshDimension())
725      {
726      case 2:
727        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
728      case 3:
729        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
730      default:
731        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
732      }
733 }
734
735 /*!
736  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
737  * this->getMeshDimension(), that bound cells of \a this mesh. In
738  * addition arrays describing correspondence between cells of \a this and the result
739  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
740  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
741  *  mesh. This method differs from buildDescendingConnectivity() in that apart
742  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
743  * result meshes. So a positive id means that order of nodes in corresponding cells
744  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
745  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
746  * i.e. cell ids are one-based.
747  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
748  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
749  * \warning For speed reasons, this method does not check if node ids in the nodal
750  *          connectivity correspond to the size of node coordinates array.
751  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
752  *          to write this mesh to the MED file, its cells must be sorted using
753  *          sortCellsInMEDFileFrmt().
754  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
755  *         each cell of \a this mesh.
756  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
757  *        dividing cell ids in \a desc into groups each referring to one
758  *        cell of \a this mesh. Its every element (except the last one) is an index
759  *        pointing to the first id of a group of cells. For example cells of the
760  *        result mesh bounding the cell #1 of \a this mesh are described by following
761  *        range of indices:
762  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
763  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
764  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
765  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
766  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
767  *         by each cell of the result mesh.
768  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
769  *        in the result mesh,
770  *        dividing cell ids in \a revDesc into groups each referring to one
771  *        cell of the result mesh the same way as \a descIndx divides \a desc.
772  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
773  *        shares the node coordinates array with \a this mesh. The caller is to
774  *        delete this mesh using decrRef() as it is no more needed.
775  *  \throw If the coordinates array is not set.
776  *  \throw If the nodal connectivity of cells is node defined.
777  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
778  *         revDescIndx == NULL.
779  *
780  *  \if ENABLE_EXAMPLES
781  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
782  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
783  *  \endif
784  * \sa buildDescendingConnectivity()
785  */
786 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
787 {
788   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
789 }
790
791 /*!
792  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
793  * For speed reasons no check of this will be done. This method calls
794  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
795  * This method lists for every cell in \b this its neighbor \b cells. To compute the result
796  * only connectivities are considered.
797  * The neighbor cells of a given cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
798  * The format of return is hence \ref numbering-indirect.
799  *
800  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
801  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
802  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
803  * is equal to the last values in \b neighborsIndx.
804  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
805  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
806  */
807 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
808 {
809   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
810   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
811   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
812   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
813   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
814   meshDM1=0;
815   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
816 }
817
818 /**
819  * Given a set of identifiers indexed by the node IDs of the mesh (and given in the (\ref numbering-indirect format) ,
820  * re-arrange the data to produce a set indexed by cell IDs. The mapping between a node ID and a cell ID is done using the connectivity
821  * of the mesh (e.g. a triangular element will receive the information from its three vertices).
822  * Doublons are eliminated. If present in the inital dataset, the ID of the cell itself is also remooved.
823  *
824  * \param [in] nodeNeigh a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
825  * \param [in] nodeNeighI a set of identifiers (mcIdType) stored by node index (\ref numbering-indirect format)
826  * \param [out] cellNeigh This array is newly allocated and should be dealt by the caller. It contains the initial identifiers
827  * provided in the input parameters but stored now by cell index (See 2nd output parameter and \ref numbering-indirect).
828  * \param [out] cellNeighI is an array of size this->getNumberOfCells()+1 newly allocated and should be
829  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
830  *
831  * \raise if the number of tuples in nodeNeighI is not equal to the number of nodes in the mesh.
832  */
833 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI,
834                                                            MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
835 {
836   if(!nodeNeigh || !nodeNeighI)
837     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
838   checkConsistencyLight();
839   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
840   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
841   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
842   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
843   mcIdType nbCells=getNumberOfCells();
844   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
845   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
846   for(mcIdType i=0;i<nbCells;i++)
847     {
848       std::set<mcIdType> s;
849       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
850         if(*it>=0)  // avoid -1 in polygons or polyedrons
851           s.insert(ne+nei[*it],ne+nei[*it+1]);
852       s.erase(i);
853       cellNeigh->insertAtTheEnd(s.begin(),s.end());
854       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
855     }
856 }
857
858 /*!
859  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
860  * of MEDCouplingUMesh::computeNeighborsOfCells.
861  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
862  * typically the case to extract a set a neighbours,
863  * excluding a set of meshdim-1 cells in input descending connectivity.
864  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
865  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
866  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
867  * are considered.
868  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
869  *
870  * \param [in] desc descending connectivity array.
871  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
872  * \param [in] revDesc reverse descending connectivity array.
873  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
874  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
875  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
876  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
877  */
878 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
879                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
880 {
881   if(!desc || !descIndx || !revDesc || !revDescIndx)
882     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
883   const mcIdType *descPtr=desc->begin();
884   const mcIdType *descIPtr=descIndx->begin();
885   const mcIdType *revDescPtr=revDesc->begin();
886   const mcIdType *revDescIPtr=revDescIndx->begin();
887   //
888   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
889   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
890   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
891   mcIdType *out1Ptr=out1->getPointer();
892   *out1Ptr++=0;
893   out0->reserve(desc->getNumberOfTuples());
894   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
895     {
896       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
897         {
898           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
899           s.erase(i);
900           out0->insertAtTheEnd(s.begin(),s.end());
901         }
902       *out1Ptr=out0->getNumberOfTuples();
903     }
904   neighbors=out0.retn();
905   neighborsIndx=out1.retn();
906 }
907
908 /*!
909  * Explodes \a this into edges whatever its dimension.
910  */
911 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
912 {
913   checkFullyDefined();
914   int mdim(getMeshDimension());
915   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
916   MCAuto<MEDCouplingUMesh> mesh1D;
917   switch(mdim)
918   {
919     case 3:
920       {
921         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
922         break;
923       }
924     case 2:
925       {
926         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
927         break;
928       }
929     default:
930       {
931         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
932       }
933   }
934   return mesh1D;
935 }
936
937 /*!
938  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
939  * For speed reasons no check of this will be done. This method calls
940  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
941  * This method lists for every node in \b this its neighbor \b nodes. To compute the result
942  * only connectivities are considered.
943  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
944  *
945  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
946  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
947  * parameter allows to select the right part in this array (\ref numbering-indirect).
948  * The number of tuples is equal to the last values in \b neighborsIndx.
949  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
950  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
951  *
952  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
953  */
954 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
955 {
956   checkFullyDefined();
957   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
958   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
959   MCConstAuto<MEDCouplingUMesh> mesh1D;
960   switch(mdim)
961   {
962     case 3:
963       {
964         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
965         break;
966       }
967     case 2:
968       {
969         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
970         break;
971       }
972     case 1:
973       {
974         mesh1D.takeRef(this);
975         break;
976       }
977     default:
978       {
979         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
980       }
981   }
982   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
983   mesh1D->getReverseNodalConnectivity(desc,descIndx);
984   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
985   ret0->alloc(desc->getNumberOfTuples(),1);
986   mcIdType *r0Pt(ret0->getPointer());
987   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
988   for(mcIdType i=0;i<nbNodes;i++,rni++)
989     {
990       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
991         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
992     }
993   neighbors=ret0.retn();
994   neighborsIdx=descIndx.retn();
995 }
996
997 /*!
998  * Computes enlarged neighbors for each nodes in \a this. The behavior of this method is close to MEDCouplingUMesh::computeNeighborsOfNodes except that the neighborhood of each node is wider here.
999  * A node j is considered to be in the neighborhood of i if and only if there is a cell in \a this containing in its nodal connectivity both i and j.
1000  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
1001  *
1002  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
1003  */
1004 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
1005 {
1006   checkFullyDefined();
1007   mcIdType nbOfNodes(getNumberOfNodes());
1008   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
1009   mcIdType nbOfCells=getNumberOfCells();
1010   std::vector< std::set<mcIdType> > st0(nbOfNodes);
1011   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
1012     {
1013       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
1014       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
1015       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
1016         st0[*iter2].insert(s.begin(),s.end());
1017     }
1018   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
1019   {
1020     mcIdType *neighIdx(neighborsIdx->getPointer());
1021     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
1022       {
1023         if ((*it).empty())
1024           neighIdx[1]=neighIdx[0];
1025         else
1026           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
1027       }
1028   }
1029   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
1030   {
1031     const mcIdType *neighIdx(neighborsIdx->begin());
1032     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
1033     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
1034       {
1035         std::set<mcIdType> s(*it); s.erase(nodeId);
1036         std::copy(s.begin(),s.end(),neigh+*neighIdx);
1037       }
1038   }
1039 }
1040
1041 /*!
1042  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1043  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1044  * array of cell ids. Pay attention that after conversion all algorithms work slower
1045  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1046  * conversion due presence of invalid ids in the array of cells to convert, as a
1047  * result \a this mesh contains some already converted elements. In this case the 2D
1048  * mesh remains valid but 3D mesh becomes \b inconsistent!
1049  *  \warning This method can significantly modify the order of geometric types in \a this,
1050  *          hence, to write this mesh to the MED file, its cells must be sorted using
1051  *          sortCellsInMEDFileFrmt().
1052  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1053  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1054  *         cellIdsToConvertBg.
1055  *  \throw If the coordinates array is not set.
1056  *  \throw If the nodal connectivity of cells is node defined.
1057  *  \throw If dimension of \a this mesh is not either 2 or 3.
1058  *
1059  *  \if ENABLE_EXAMPLES
1060  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1061  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1062  *  \endif
1063  */
1064 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1065 {
1066   checkFullyDefined();
1067   int dim=getMeshDimension();
1068   if(dim<2 || dim>3)
1069     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1070   mcIdType nbOfCells=getNumberOfCells();
1071   if(dim==2)
1072     {
1073       const mcIdType *connIndex=_nodal_connec_index->begin();
1074       mcIdType *conn=_nodal_connec->getPointer();
1075       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1076         {
1077           if(*iter>=0 && *iter<nbOfCells)
1078             {
1079               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1080               if(!cm.isQuadratic())
1081                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1082               else
1083                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1084             }
1085           else
1086             {
1087               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1088               oss << " in range [0," << nbOfCells << ") !";
1089               throw INTERP_KERNEL::Exception(oss.str());
1090             }
1091         }
1092     }
1093   else
1094     {
1095       mcIdType *connIndex(_nodal_connec_index->getPointer());
1096       const mcIdType *connOld(_nodal_connec->getConstPointer());
1097       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1098       std::vector<bool> toBeDone(nbOfCells,false);
1099       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1100         {
1101           if(*iter>=0 && *iter<nbOfCells)
1102             toBeDone[*iter]=true;
1103           else
1104             {
1105               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1106               oss << " in range [0," << nbOfCells << ") !";
1107               throw INTERP_KERNEL::Exception(oss.str());
1108             }
1109         }
1110       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1111         {
1112           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1113           mcIdType lgthOld(posP1-pos-1);
1114           if(toBeDone[cellId])
1115             {
1116               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1117               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1118               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1119               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1120               for(unsigned j=0;j<nbOfFaces;j++)
1121                 {
1122                   INTERP_KERNEL::NormalizedCellType type;
1123                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1124                   work+=offset;
1125                   *work++=-1;
1126                 }
1127               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1128               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1129               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1130               delete [] tmp;
1131             }
1132           else
1133             {
1134               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1135               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1136             }
1137         }
1138       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1139     }
1140   computeTypes();
1141 }
1142
1143 /*!
1144  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1145  * polyhedrons (if \a this is a 3D mesh).
1146  *  \warning As this method is purely for user-friendliness and no optimization is
1147  *          done to avoid construction of a useless vector, this method can be costly
1148  *          in memory.
1149  *  \throw If the coordinates array is not set.
1150  *  \throw If the nodal connectivity of cells is node defined.
1151  *  \throw If dimension of \a this mesh is not either 2 or 3.
1152  */
1153 void MEDCouplingUMesh::convertAllToPoly()
1154 {
1155   mcIdType nbOfCells=getNumberOfCells();
1156   std::vector<mcIdType> cellIds(nbOfCells);
1157   for(mcIdType i=0;i<nbOfCells;i++)
1158     cellIds[i]=i;
1159   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1160 }
1161
1162 /*!
1163  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1164  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1165  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1166  * base facet of the volume and the second half of nodes describes an opposite facet
1167  * having the same number of nodes as the base one. This method converts such
1168  * connectivity to a valid polyhedral format where connectivity of each facet is
1169  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1170  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1171  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1172  * a correct orientation of the first facet of a polyhedron, else orientation of a
1173  * corrected cell is reverse.<br>
1174  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1175  * it releases the user from boring description of polyhedra connectivity in the valid
1176  * format.
1177  *  \throw If \a this->getMeshDimension() != 3.
1178  *  \throw If \a this->getSpaceDimension() != 3.
1179  *  \throw If the nodal connectivity of cells is not defined.
1180  *  \throw If the coordinates array is not set.
1181  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1182  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1183  *
1184  *  \if ENABLE_EXAMPLES
1185  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1186  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1187  *  \endif
1188  */
1189 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1190 {
1191   checkFullyDefined();
1192   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1193     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1194   mcIdType nbOfCells=getNumberOfCells();
1195   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1196   newCi->alloc(nbOfCells+1,1);
1197   mcIdType *newci=newCi->getPointer();
1198   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1199   const mcIdType *c=_nodal_connec->getConstPointer();
1200   newci[0]=0;
1201   for(mcIdType i=0;i<nbOfCells;i++)
1202     {
1203       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1204       if(type==INTERP_KERNEL::NORM_POLYHED)
1205         {
1206           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1207             {
1208               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1209               throw INTERP_KERNEL::Exception(oss.str());
1210             }
1211           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1212           if(n2%2!=0)
1213             {
1214               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron with 1 face but there is a mismatch of number of nodes in face should be even !";
1215               throw INTERP_KERNEL::Exception(oss.str());
1216             }
1217           mcIdType n1=ToIdType(n2/2);
1218           newci[i+1]=7*n1+2+newci[i];//6*n1 (nodal length) + n1+2 (number of faces) - 1 (number of '-1' separator is equal to number of faces -1) + 1 (for cell type)
1219         }
1220       else
1221         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1222     }
1223   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1224   newC->alloc(newci[nbOfCells],1);
1225   mcIdType *newc=newC->getPointer();
1226   for(mcIdType i=0;i<nbOfCells;i++)
1227     {
1228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1229       if(type==INTERP_KERNEL::NORM_POLYHED)
1230         {
1231           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1232           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1233           *newc++=-1;
1234           for(std::size_t j=0;j<n1;j++)
1235             {
1236               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1237               newc[n1+5*j]=-1;
1238               newc[n1+5*j+1]=c[ci[i]+1+j];
1239               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1240               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1241               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1242             }
1243           newc+=n1*6;
1244         }
1245       else
1246         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1247     }
1248   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1249   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1250 }
1251
1252
1253 /*!
1254  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1255  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1256  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1257  *          to write this mesh to the MED file, its cells must be sorted using
1258  *          sortCellsInMEDFileFrmt().
1259  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1260  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1261  * \return \c true if at least one cell has been converted, \c false else. In the
1262  *         last case the nodal connectivity remains unchanged.
1263  * \throw If the coordinates array is not set.
1264  * \throw If the nodal connectivity of cells is not defined.
1265  * \throw If \a this->getMeshDimension() < 0.
1266  */
1267 bool MEDCouplingUMesh::unPolyze()
1268 {
1269   checkFullyDefined();
1270   int mdim=getMeshDimension();
1271   if(mdim<0)
1272     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1273   if(mdim<=1)
1274     return false;
1275   mcIdType nbOfCells=getNumberOfCells();
1276   if(nbOfCells<1)
1277     return false;
1278   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1279   mcIdType *conn=_nodal_connec->getPointer();
1280   mcIdType *index=_nodal_connec_index->getPointer();
1281   mcIdType posOfCurCell=0;
1282   mcIdType newPos=0;
1283   mcIdType lgthOfCurCell;
1284   bool ret=false;
1285   for(mcIdType i=0;i<nbOfCells;i++)
1286     {
1287       lgthOfCurCell=index[i+1]-posOfCurCell;
1288       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1289       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1290       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1291       mcIdType newLgth=0;
1292       if(cm.isDynamic())
1293         {
1294           switch(cm.getDimension())
1295           {
1296             case 2:
1297               {
1298                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1299                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1300                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1301                 break;
1302               }
1303             case 3:
1304               {
1305                 mcIdType nbOfFaces,lgthOfPolyhConn;
1306                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1307                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1308                 break;
1309               }
1310          /*   case 1:  // Not supported yet
1311               {
1312                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1313                 break;
1314               }
1315          */
1316           }
1317           ret=ret || (newType!=type);
1318           conn[newPos]=newType;
1319           newPos+=newLgth+1;
1320           posOfCurCell=index[i+1];
1321           index[i+1]=newPos;
1322         }
1323       else
1324         {
1325           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1326           newPos+=lgthOfCurCell;
1327           posOfCurCell+=lgthOfCurCell;
1328           index[i+1]=newPos;
1329         }
1330     }
1331   if(newPos!=initMeshLgth)
1332     _nodal_connec->reAlloc(newPos);
1333   if(ret)
1334     computeTypes();
1335   return ret;
1336 }
1337
1338 /*!
1339  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1340  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1341  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1342  *
1343  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not. This epsilon is used to recenter around origin to have maximal
1344  *             precision.
1345  */
1346 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1347 {
1348   checkFullyDefined();
1349   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1351   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1352   coords->recenterForMaxPrecision(eps);
1353   //
1354   mcIdType nbOfCells=getNumberOfCells();
1355   const mcIdType *conn=_nodal_connec->getConstPointer();
1356   const mcIdType *index=_nodal_connec_index->getConstPointer();
1357   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1358   connINew->alloc(nbOfCells+1,1);
1359   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1360   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1361   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1362   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1363   bool changed=false;
1364   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1365     {
1366       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1367         {
1368           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1369           changed=true;
1370         }
1371       else
1372         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1373       *connINewPtr=connNew->getNumberOfTuples();
1374     }
1375   if(changed)
1376     setConnectivity(connNew,connINew,false);
1377 }
1378
1379 /*!
1380  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1381  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1382  * the format of the returned DataArrayIdType instance.
1383  *
1384  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1385  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1386  */
1387 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1388 {
1389   checkConnectivityFullyDefined();
1390   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1391   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1392   std::vector<bool> retS(maxElt,false);
1393   computeNodeIdsAlg(retS);
1394   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1395 }
1396
1397 /*!
1398  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1399  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1400  */
1401 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1402 {
1403   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1404            nbOfCells=getNumberOfCells();
1405   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1406   for(mcIdType i=0;i<nbOfCells;i++)
1407     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1408       if(conn[j]>=0)
1409         {
1410           if(conn[j]<nbOfNodes)
1411             nodeIdsInUse[conn[j]]=true;
1412           else
1413             {
1414               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1415               throw INTERP_KERNEL::Exception(oss.str());
1416             }
1417         }
1418 }
1419
1420 /// @cond INTERNAL
1421
1422 struct MEDCouplingAccVisit
1423 {
1424   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1425   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1426   mcIdType _new_nb_of_nodes;
1427 };
1428
1429 /// @endcond
1430
1431 /*!
1432  * Finds nodes not used in any cell and returns an array giving a new id to every node
1433  * by excluding the unused nodes, for which the array holds -1. The result array is
1434  * a mapping in "Old to New" mode.
1435  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1436  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1437  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1438  *          if the node is unused or a new id else. The caller is to delete this
1439  *          array using decrRef() as it is no more needed.
1440  *  \throw If the coordinates array is not set.
1441  *  \throw If the nodal connectivity of cells is not defined.
1442  *  \throw If the nodal connectivity includes an invalid id.
1443  *
1444  *  \if ENABLE_EXAMPLES
1445  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1446  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1447  *  \endif
1448  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1449  */
1450 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1451 {
1452   nbrOfNodesInUse=-1;
1453   mcIdType nbOfNodes(getNumberOfNodes());
1454   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1455   ret->alloc(nbOfNodes,1);
1456   mcIdType *traducer=ret->getPointer();
1457   std::fill(traducer,traducer+nbOfNodes,-1);
1458   mcIdType nbOfCells=getNumberOfCells();
1459   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1460   const mcIdType *conn=_nodal_connec->getConstPointer();
1461   for(mcIdType i=0;i<nbOfCells;i++)
1462     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1463       if(conn[j]>=0)
1464         {
1465           if(conn[j]<nbOfNodes)
1466             traducer[conn[j]]=1;
1467           else
1468             {
1469               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1470               throw INTERP_KERNEL::Exception(oss.str());
1471             }
1472         }
1473   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1474   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1475   return ret.retn();
1476 }
1477
1478 /*!
1479  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1480  * For each cell in \b this the number of nodes constituting cell is computed.
1481  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1482  * So for pohyhedrons some nodes can be counted several times in the returned result.
1483  *
1484  * \return a newly allocated array
1485  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1486  */
1487 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1488 {
1489   checkConnectivityFullyDefined();
1490   mcIdType nbOfCells=getNumberOfCells();
1491   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1492   ret->alloc(nbOfCells,1);
1493   mcIdType *retPtr=ret->getPointer();
1494   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1495   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1496   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1497     {
1498       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1499         *retPtr=connI[i+1]-connI[i]-1;
1500       else
1501         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1502     }
1503   return ret.retn();
1504 }
1505
1506 /*!
1507  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1508  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1509  *
1510  * \return DataArrayIdType * - new object to be deallocated by the caller.
1511  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1512  */
1513 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1514 {
1515   checkConnectivityFullyDefined();
1516   mcIdType nbOfCells=getNumberOfCells();
1517   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1518   ret->alloc(nbOfCells,1);
1519   mcIdType *retPtr=ret->getPointer();
1520   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1521   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1522   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1523     {
1524       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1525       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1526         *retPtr=ToIdType(s.size());
1527       else
1528         {
1529           s.erase(-1);
1530           *retPtr=ToIdType(s.size());
1531         }
1532     }
1533   return ret.retn();
1534 }
1535
1536 /*!
1537  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1538  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1539  *
1540  * \return a newly allocated array
1541  */
1542 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1543 {
1544   checkConnectivityFullyDefined();
1545   mcIdType nbOfCells=getNumberOfCells();
1546   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1547   ret->alloc(nbOfCells,1);
1548   mcIdType *retPtr=ret->getPointer();
1549   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1550   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1551   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1552     {
1553       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1554       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1555     }
1556   return ret.retn();
1557 }
1558
1559 /*!
1560  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1561  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1562  * array mean that the corresponding old node is no more used.
1563  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1564  *           this->getNumberOfNodes() before call of this method. The caller is to
1565  *           delete this array using decrRef() as it is no more needed.
1566  *  \throw If the coordinates array is not set.
1567  *  \throw If the nodal connectivity of cells is not defined.
1568  *  \throw If the nodal connectivity includes an invalid id.
1569  *  \sa areAllNodesFetched
1570  *
1571  *  \if ENABLE_EXAMPLES
1572  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1573  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1574  *  \endif
1575  */
1576 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1577 {
1578   return MEDCouplingPointSet::zipCoordsTraducer();
1579 }
1580
1581 /*!
1582  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1583  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1584  */
1585 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1586 {
1587   switch(compType)
1588   {
1589     case 0:
1590       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1591     case 1:
1592       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1593     case 2:
1594       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1595     case 3:
1596       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1597     case 7:
1598       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1599   }
1600   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1610   return 0;
1611 }
1612
1613 /*!
1614  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1615  */
1616 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1617 {
1618   mcIdType sz=connI[cell1+1]-connI[cell1];
1619   if(sz==connI[cell2+1]-connI[cell2])
1620     {
1621       if(conn[connI[cell1]]==conn[connI[cell2]])
1622         {
1623           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1624           unsigned dim=cm.getDimension();
1625           if(dim!=3)
1626             {
1627               if(dim!=1)
1628                 {
1629                   mcIdType sz1=2*(sz-1);
1630                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1631                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1632                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1633                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1634                   return work!=tmp+sz1?1:0;
1635                 }
1636               else
1637                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1638             }
1639           else
1640             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1641         }
1642     }
1643   return 0;
1644 }
1645
1646 /*!
1647  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1648  */
1649 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1650 {
1651   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1652     {
1653       if(conn[connI[cell1]]==conn[connI[cell2]])
1654         {
1655           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1656           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1657           return s1==s2?1:0;
1658         }
1659     }
1660   return 0;
1661 }
1662
1663 /*!
1664  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1665  */
1666 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1667 {
1668   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1669     {
1670       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1671       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1672       return s1==s2?1:0;
1673     }
1674   return 0;
1675 }
1676
1677 /*!
1678  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1679  */
1680 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1681 {
1682   mcIdType sz=connI[cell1+1]-connI[cell1];
1683   if(sz==connI[cell2+1]-connI[cell2])
1684     {
1685       if(conn[connI[cell1]]==conn[connI[cell2]])
1686         {
1687           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1688           unsigned dim=cm.getDimension();
1689           if(dim!=3)
1690             {
1691               if(dim!=1)
1692                 {
1693                   mcIdType sz1=2*(sz-1);
1694                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1695                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1696                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1697                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1698                   if(work!=tmp+sz1)
1699                     return 1;
1700                   else
1701                     {
1702                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1703                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1704                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1705                         return 2;
1706                       else
1707                         return 0;
1708                     }
1709                 }
1710               else
1711                 {//case of SEG2 and SEG3
1712                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1713                     return 1;
1714                   if(!cm.isQuadratic())
1715                     {
1716                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1717                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1718                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1719                         return 2;
1720                       return 0;
1721                     }
1722                   else
1723                     {
1724                       if(conn[connI[cell1]+1]==conn[connI[cell2]+2] && conn[connI[cell1]+2]==conn[connI[cell2]+1] && conn[connI[cell1]+3]==conn[connI[cell2]+3])
1725                         return 2;
1726                       return 0;
1727                     }
1728                 }
1729             }
1730           else
1731             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 /*!
1739  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1740  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1741  * If \a startCellId is equal to 0 algorithm starts at cell #0 and for each cell candidates being searched have cell id higher than current cellId.
1742  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1743  * This method is time consuming.
1744  *
1745  * \param [in] compType input specifying the technique used to compare cells each other.
1746  *   - 0 : exactly. A cell is detected to be the same if and only if the connectivity is exactly the same without permutation and types same too. This is the strongest policy.
1747  *   - 1 : permutation same orientation. cell1 and cell2 are considered equal if the connectivity of cell2 can be deduced by those of cell1 by direct permutation (with exactly the same orientation)
1748  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1749  *   - 2 : nodal. cell1 and cell2 are equal if and only if cell1 and cell2 have same type and have the same nodes constituting connectivity. This is the laziest policy. This policy
1750  * can be used for users not sensitive to orientation of cell
1751  * \param [in] startCellId specifies the cellId starting from which the equality computation will be carried out. By default it is 0, which it means that all cells in \a this will be scanned.
1752  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1753  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1754  *
1755  */
1756 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1757 {
1758   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1759   getReverseNodalConnectivity(revNodal,revNodalI);
1760   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1761 }
1762
1763 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1764                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1765 {
1766   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1767   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1768   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1769   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1770   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1771   std::vector<bool> isFetched(nbOfCells,false);
1772   if(startCellId==0)
1773     {
1774       for(mcIdType i=startCellId;i<nbOfCells;i++)
1775         {
1776           if(!isFetched[i])
1777             {
1778               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1779               std::vector<mcIdType> v,v2;
1780               if(connOfNode!=connPtr+connIPtr[i+1])
1781                 {
1782                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1783                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1784                   connOfNode++;
1785                 }
1786               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1787                 if(*connOfNode>=0)
1788                   {
1789                     v=v2;
1790                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1791                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1792                     v2.resize(std::distance(v2.begin(),it));
1793                   }
1794               if(v2.size()>1)
1795                 {
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType pos=commonCellsI->back();
1799                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1800                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1801                         isFetched[*it]=true;
1802                     }
1803                 }
1804             }
1805         }
1806     }
1807   else
1808     {
1809       for(mcIdType i=startCellId;i<nbOfCells;i++)
1810         {
1811           if(!isFetched[i])
1812             {
1813               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1));
1814               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1815               std::vector<mcIdType> v,v2;
1816               if(connOfNode!=connPtr+connIPtr[i+1])
1817                 {
1818                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1819                   connOfNode++;
1820                 }
1821               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1822                 if(*connOfNode>=0)
1823                   {
1824                     v=v2;
1825                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1826                     v2.resize(std::distance(v2.begin(),it));
1827                   }
1828               // v2 contains now candidates. Problem candidates are sorted using id rank.
1829               if(v2.size()>1)
1830                 {
1831                   if(v2[0]!=i)
1832                   {
1833                     auto it(std::find(v2.begin(),v2.end(),i));
1834                     std::swap(*v2.begin(),*it);
1835                   }
1836                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1837                     {
1838                       mcIdType newPos(commonCells->getNumberOfTuples());
1839                       mcIdType pos(commonCellsI->back());
1840                       std::sort(commonCells->getPointerSilent()+pos,commonCells->getPointerSilent()+newPos);
1841                       commonCellsI->pushBackSilent(newPos);
1842                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1843                         isFetched[*it]=true;
1844                     }
1845                 }
1846             }
1847         }
1848     }
1849   commonCellsArr=commonCells.retn();
1850   commonCellsIArr=commonCellsI.retn();
1851 }
1852
1853 /*!
1854  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1855  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1856  * than \a this->getNumberOfCells() in the returned array means that there is no
1857  * corresponding cell in \a this mesh.
1858  * It is expected that \a this and \a other meshes share the same node coordinates
1859  * array, if it is not so an exception is thrown.
1860  *  \param [in] other - the mesh to compare with.
1861  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1862  *         valid values [0,1,2], see zipConnectivityTraducer().
1863  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1864  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1865  *         values. The caller is to delete this array using
1866  *         decrRef() as it is no more needed.
1867  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1868  *         mesh.
1869  *
1870  *  \if ENABLE_EXAMPLES
1871  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1872  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1873  *  \endif
1874  *  \sa checkDeepEquivalOnSameNodesWith()
1875  *  \sa checkGeoEquivalWith()
1876  */
1877 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1878 {
1879   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1880   mcIdType nbOfCells=getNumberOfCells();
1881   static const int possibleCompType[]={0,1,2};
1882   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1883     {
1884       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1885       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1886       oss << " !";
1887       throw INTERP_KERNEL::Exception(oss.str());
1888     }
1889   //
1890   if(other->getNumberOfCells()==0)
1891   {
1892     MCAuto<DataArrayIdType> dftRet(DataArrayIdType::New()); dftRet->alloc(0,1); arr=dftRet.retn(); arr->setName(other->getName());
1893     return true;
1894   }
1895   DataArrayIdType *commonCells(nullptr),*commonCellsI(nullptr);
1896   mesh->findCommonCells(compType,nbOfCells,commonCells,commonCellsI);
1897   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1898   mcIdType newNbOfCells=-1;
1899   MCAuto<DataArrayIdType> o2n = DataArrayIdType::ConvertIndexArrayToO2N(ToIdType(mesh->getNumberOfCells()),commonCells->begin(),commonCellsI->begin(),commonCellsI->end(),newNbOfCells);
1900   MCAuto<DataArrayIdType> p0(o2n->selectByTupleIdSafeSlice(0,nbOfCells,1));
1901   mcIdType maxPart(p0->getMaxValueInArray());
1902   bool ret(maxPart==newNbOfCells-1);
1903   MCAuto<DataArrayIdType> p1(p0->invertArrayO2N2N2O(newNbOfCells));
1904   // fill p1 array in case of presence of cells in other not in this
1905   mcIdType *pt(p1->getPointer());
1906   for(mcIdType i = maxPart ; i < newNbOfCells-1 ; ++i )
1907     pt[i+1] = i+1;
1908   //
1909   MCAuto<DataArrayIdType> p2(o2n->subArray(nbOfCells));
1910   p2->transformWithIndArr(p1->begin(),p1->end()); p2->setName(other->getName());
1911   arr = p2.retn();
1912   return ret;
1913 }
1914
1915 /*!
1916  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1917  * This method tries to determine if \b other is fully included in \b this.
1918  * The main difference is that this method is not expected to throw exception.
1919  * This method has two outputs :
1920  *
1921  * \param other other mesh
1922  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1923  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1924  */
1925 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1926 {
1927   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1928   DataArrayIdType *commonCells=0,*commonCellsI=0;
1929   mcIdType thisNbCells=getNumberOfCells();
1930   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1931   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1932   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1933   mcIdType otherNbCells=other->getNumberOfCells();
1934   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1935   arr2->alloc(otherNbCells,1);
1936   arr2->fillWithZero();
1937   mcIdType *arr2Ptr=arr2->getPointer();
1938   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1939   for(mcIdType i=0;i<nbOfCommon;i++)
1940     {
1941       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1942       if(start<thisNbCells)
1943         {
1944           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1945             {
1946               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1947               mcIdType val=std::abs(commonCellsPtr[j])-1;
1948               if(val>=thisNbCells)
1949                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1950             }
1951         }
1952     }
1953   arr2->setName(other->getName());
1954   if(arr2->presenceOfValue(0))
1955     return false;
1956   arr=arr2.retn();
1957   return true;
1958 }
1959
1960 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1961 {
1962   if(!other)
1963     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1964   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1965   if(!otherC)
1966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1967   std::vector<const MEDCouplingUMesh *> ms(2);
1968   ms[0]=this;
1969   ms[1]=otherC;
1970   return MergeUMeshesOnSameCoords(ms);
1971 }
1972
1973 /*!
1974  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1975  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1976  * cellIds is not given explicitly but by a range python like.
1977  *
1978  * \param start starting ID
1979  * \param end end ID (excluded)
1980  * \param step step size
1981  * \param keepCoords that specifies if you want or not to keep coords as this or zip it (see MEDCoupling::MEDCouplingUMesh::zipCoords). If true zipCoords is \b NOT called, if false, zipCoords is called.
1982  * \return a newly allocated
1983  *
1984  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1985  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1986  */
1987 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1988 {
1989   if(getMeshDimension()!=-1)
1990     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1991   else
1992     {
1993       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1994       if(newNbOfCells!=1)
1995         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1996       if(start!=0)
1997         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1998       incrRef();
1999       return const_cast<MEDCouplingUMesh *>(this);
2000     }
2001 }
2002
2003 /*!
2004  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2005  * The result mesh shares or not the node coordinates array with \a this mesh depending
2006  * on \a keepCoords parameter.
2007  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2008  *           to write this mesh to the MED file, its cells must be sorted using
2009  *           sortCellsInMEDFileFrmt().
2010  *  \param [in] begin - an array of cell ids to include to the new mesh.
2011  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2012  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2013  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2014  *         by calling zipCoords().
2015  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2016  *         to delete this mesh using decrRef() as it is no more needed.
2017  *  \throw If the coordinates array is not set.
2018  *  \throw If the nodal connectivity of cells is not defined.
2019  *  \throw If any cell id in the array \a begin is not valid.
2020  *
2021  *  \if ENABLE_EXAMPLES
2022  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2023  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2024  *  \endif
2025  */
2026 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
2027 {
2028   if(getMeshDimension()!=-1)
2029     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2030   else
2031     {
2032       if(end-begin!=1)
2033         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2034       if(begin[0]!=0)
2035         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2036       incrRef();
2037       return const_cast<MEDCouplingUMesh *>(this);
2038     }
2039 }
2040
2041 /*!
2042  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2043  *
2044  * This method allows to partially modify some cells in \b this (whose list is specified by [ \b cellIdsBg, \b cellIdsEnd ) ) with cells coming in \b otherOnSameCoordsThanThis.
2045  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2046  * The number of cells of \b this will remain the same with this method.
2047  *
2048  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2049  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2050  * \param [in] otherOnSameCoordsThanThis an another mesh with same meshdimension than \b this with exactly the same number of cells than cell ids list in [\b cellIdsBg, \b cellIdsEnd ).
2051  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2052  */
2053 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2054 {
2055   checkConnectivityFullyDefined();
2056   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2057   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2058     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2059   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2060     {
2061       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2062       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2063       throw INTERP_KERNEL::Exception(oss.str());
2064     }
2065   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2066   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2067     {
2068       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2069       throw INTERP_KERNEL::Exception(oss.str());
2070     }
2071   mcIdType nbOfCells(getNumberOfCells());
2072   bool easyAssign(true);
2073   const mcIdType *connI(_nodal_connec_index->begin());
2074   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2075   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2076     {
2077       if(*it>=0 && *it<nbOfCells)
2078         {
2079           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2080         }
2081       else
2082         {
2083           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2084           throw INTERP_KERNEL::Exception(oss.str());
2085         }
2086     }
2087   if(easyAssign)
2088     {
2089       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2090       computeTypes();
2091     }
2092   else
2093     {
2094       DataArrayIdType *arrOut=0,*arrIOut=0;
2095       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2096                                                arrOut,arrIOut);
2097       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2098       setConnectivity(arrOut,arrIOut,true);
2099     }
2100 }
2101
2102 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2103 {
2104   checkConnectivityFullyDefined();
2105   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2106   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2108   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2109     {
2110       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2111       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2112       throw INTERP_KERNEL::Exception(oss.str());
2113     }
2114   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2115   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2116     {
2117       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2118       throw INTERP_KERNEL::Exception(oss.str());
2119     }
2120   mcIdType nbOfCells=getNumberOfCells();
2121   bool easyAssign=true;
2122   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2123   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2124   mcIdType it=start;
2125   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2126     {
2127       if(it>=0 && it<nbOfCells)
2128         {
2129           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2130         }
2131       else
2132         {
2133           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2134           throw INTERP_KERNEL::Exception(oss.str());
2135         }
2136     }
2137   if(easyAssign)
2138     {
2139       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2140       computeTypes();
2141     }
2142   else
2143     {
2144       DataArrayIdType *arrOut=0,*arrIOut=0;
2145       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2146                                                 arrOut,arrIOut);
2147       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2148       setConnectivity(arrOut,arrIOut,true);
2149     }
2150 }
2151
2152
2153 /*!
2154  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2155  * this->getMeshDimension(), that bound some cells of \a this mesh.
2156  * The cells of lower dimension to include to the result mesh are selected basing on
2157  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2158  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2159  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2160  * created mesh shares the node coordinates array with \a this mesh.
2161  *  \param [in] begin - the array of node ids.
2162  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2163  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2164  *         array \a begin are added, else cells whose any node is in the
2165  *         array \a begin are added.
2166  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2167  *         to delete this mesh using decrRef() as it is no more needed.
2168  *  \throw If the coordinates array is not set.
2169  *  \throw If the nodal connectivity of cells is not defined.
2170  *  \throw If any node id in \a begin is not valid.
2171  *
2172  *  \if ENABLE_EXAMPLES
2173  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2174  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2175  *  \endif
2176  */
2177 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2178 {
2179   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2180   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2181   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2182   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2183   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2184 }
2185
2186 /*!
2187  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2188  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2189  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2190  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2191  *         by calling zipCoords().
2192  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2193  *         to delete this mesh using decrRef() as it is no more needed.
2194  *  \throw If the coordinates array is not set.
2195  *  \throw If the nodal connectivity of cells is not defined.
2196  *
2197  *  \if ENABLE_EXAMPLES
2198  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2199  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2200  *  \endif
2201  */
2202 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2203 {
2204   DataArrayIdType *desc=DataArrayIdType::New();
2205   DataArrayIdType *descIndx=DataArrayIdType::New();
2206   DataArrayIdType *revDesc=DataArrayIdType::New();
2207   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2208   //
2209   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2210   revDesc->decrRef();
2211   desc->decrRef();
2212   descIndx->decrRef();
2213   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2214   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2215   std::vector<mcIdType> boundaryCells;
2216   for(mcIdType i=0;i<nbOfCells;i++)
2217     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2218       boundaryCells.push_back(i);
2219   revDescIndx->decrRef();
2220   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2221   return ret;
2222 }
2223
2224 /*!
2225  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2226  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2227  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2228  */
2229 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2230 {
2231   checkFullyDefined();
2232   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2233   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2234   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2235   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2236   //
2237   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2238   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2239   //
2240   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2241   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2242   const mcIdType *revDescPtr=revDesc->getConstPointer();
2243   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2244   mcIdType nbOfCells=getNumberOfCells();
2245   std::vector<bool> ret1(nbOfCells,false);
2246   mcIdType sz=0;
2247   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2248     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2249       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2250   //
2251   DataArrayIdType *ret2=DataArrayIdType::New();
2252   ret2->alloc(sz,1);
2253   mcIdType *ret2Ptr=ret2->getPointer();
2254   sz=0;
2255   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2256     if(*it)
2257       *ret2Ptr++=sz;
2258   ret2->setName("BoundaryCells");
2259   return ret2;
2260 }
2261
2262 /*!
2263  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2264  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2265  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2266  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2267  *
2268  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2269  * This method also returns the cells ids set s1 which contains the cell ids in \b this for which one of the dim-1 constituent
2270  * equals a cell in \b otherDimM1OnSameCoords.
2271  *
2272  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2273  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2274  *
2275  * \param [in] otherDimM1OnSameCoords other mesh
2276  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2277  * \param [out] cellIdsRk1 a newly allocated array containing the cell ids of s1 \b indexed into the \b cellIdsRk0 subset. To get the absolute ids of s1, simply invoke
2278  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2279  */
2280 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2281 {
2282   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2283     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2284   checkConnectivityFullyDefined();
2285   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2286   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2287     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2288   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2289   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2290   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2291   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2292   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2293   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2294   DataArrayIdType *idsOtherInConsti=0;
2295   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2296   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2297   if(!b)
2298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2299   std::set<mcIdType> s1;
2300   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2301     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2302   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2303   s1arr_renum1->sort();
2304   cellIdsRk0=s0arr.retn();
2305   //cellIdsRk1=s_renum1.retn();
2306   cellIdsRk1=s1arr_renum1.retn();
2307 }
2308
2309 /*!
2310  * This method computes the skin of \b this. That is to say the consituting meshdim-1 mesh is built and only the boundary subpart is
2311  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2312  *
2313  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2314  */
2315 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2316 {
2317   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2318   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2319   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2320   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2321   //
2322   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2323   revDesc=0; desc=0; descIndx=0;
2324   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2325   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2326   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2327 }
2328
2329 /*!
2330  * Finds nodes lying on the boundary of \a this mesh.
2331  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2332  *          nodes. The caller is to delete this array using decrRef() as it is no
2333  *          more needed.
2334  *  \throw If the coordinates array is not set.
2335  *  \throw If the nodal connectivity of cells is node defined.
2336  *
2337  *  \if ENABLE_EXAMPLES
2338  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2339  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2340  *  \endif
2341  */
2342 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2343 {
2344   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2345   return skin->computeFetchedNodeIds();
2346 }
2347
2348 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2349 {
2350   incrRef();
2351   return const_cast<MEDCouplingUMesh *>(this);
2352 }
2353
2354 /*!
2355  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2356  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2357  * This method searches for nodes needed to be duplicated. Those are the 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, it will 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] crackingMesh a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
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& crackingMesh) 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   crackingMesh.checkFullyDefined();
2375   if(getCoords()!=crackingMesh.getCoords())
2376     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2377   if(crackingMesh.getMeshDimension()!=getMeshDimension()-1)
2378     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2379
2380   // Clean the M1 group (cracking mesh): the M1 cells which are part of M0 boundary are irrelevant (we can't create a crack on the boundary of M0!)
2381   MCUMesh m0skin = computeSkin();
2382   DataArrayIdType *idsToKeepP;
2383   m0skin->areCellsIncludedIn(&crackingMesh,2, idsToKeepP);
2384   DAInt idsToKeep(idsToKeepP);
2385   DAInt ids2 = idsToKeep->findIdsNotInRange(0, m0skin->getNumberOfCells());  // discard cells on the skin of M0
2386   MCUMesh otherDimM1OnSameCoords =static_cast<MEDCouplingUMesh *>(crackingMesh.buildPartOfMySelf(ids2->begin(), ids2->end(), true));
2387
2388   if (!otherDimM1OnSameCoords->getNumberOfCells())
2389     return MCAuto<DataArrayIdType>(DataArrayIdType::New()).retn();
2390
2391   // Checking star-shaped M1 group:
2392   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2393   MCUMesh meshM2 = otherDimM1OnSameCoords->buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); // 2D: a mesh of points, 3D: a mesh of segs
2394   DAInt dsi = rdit0->deltaShiftIndex();
2395   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.
2396   if(idsTmp0->getNumberOfTuples())
2397     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2398   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2399
2400   // Get extreme nodes from the group (they won't be duplicated except if they also lie on bound of M0 -- see below),
2401   // ie nodes belonging to the boundary "cells" (might be points) of M1
2402   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2403   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2404   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2405   // Remove from the list points on the boundary of the M0 mesh (those need duplication!).
2406   //    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)
2407   //    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
2408   //    although they are technically on the skin of the cube.
2409   DAInt fNodes = m0skin->computeFetchedNodeIds();
2410   DAInt notDup = 0;
2411   if (getMeshDimension() == 3)
2412     {
2413       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2414       MCUMesh m0skinDesc = m0skin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4); // all segments of the skin of the 3D (M0) mesh
2415       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2416       DataArrayIdType * corresp=0;
2417       meshM2->areCellsIncludedIn(m0skinDesc,2,corresp);
2418       // validIds is the list of segments which are on both the skin of *this*, and in the segments of the M1 group
2419       // In the cube example above, this is a U-shaped polyline.
2420       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2421       corresp->decrRef();
2422       if (validIds->getNumberOfTuples())
2423         {
2424           // 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:
2425           // (the U-shaped polyline described above)
2426           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0skinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2427           // Its boundary nodes should no be duplicated (this is for example the tip of the crack inside the cube described above)
2428           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2429           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2430
2431           // Specific logic to handle singular points :
2432           //   - a point on this U-shape line used in a cell which has no face in common with M1 is deemed singular.
2433           //   - indeed, if duplicated, such a point would lead to the duplication of a cell which has no face touching M1 ! The
2434           //   algorithm would be duplicating too much ...
2435           // 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:
2436           dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), rdit0=DataArrayIdType::New();
2437           MCUMesh meshM2Desc = meshM2->buildDescendingConnectivity(dnu1, dnu2, dnu3, rdit0);  // a mesh made of node cells
2438           dnu1=0;dnu2=0;dnu3=0;
2439           dsi = rdit0->deltaShiftIndex();  rdit0=0;
2440           DAInt singPoints = dsi->findIdsNotInRange(-1,4) ;    dsi=0;// points connected to (strictly) more than 3 segments
2441           if (singPoints->getNumberOfTuples())
2442             {
2443               DAInt boundNodes = m1IntersecSkin->computeFetchedNodeIds();
2444               // If a point on this U-shape line is connected to cells which do not share any face with M1, then it
2445               // should not be duplicated
2446               //    1. Extract N D cells touching U-shape line:
2447               DAInt cellsAroundBN = getCellIdsLyingOnNodes(boundNodes->begin(), boundNodes->end(), false);  // false= take cell in, even if not all nodes are in dupl
2448               MCUMesh mAroundBN = static_cast<MEDCouplingUMesh *>(this->buildPartOfMySelf(cellsAroundBN->begin(), cellsAroundBN->end(), true));
2449               DAInt descBN=DataArrayIdType::New(), descIBN=DataArrayIdType::New(), revDescBN=DataArrayIdType::New(), revDescIBN=DataArrayIdType::New();
2450               MCUMesh mAroundBNDesc = mAroundBN->buildDescendingConnectivity(descBN,descIBN,revDescBN,revDescIBN);
2451               //    2. Identify cells in sub-mesh mAroundBN which have a face in common with M1
2452               DataArrayIdType *idsOfM1BNt;
2453               mAroundBNDesc->areCellsIncludedIn(otherDimM1OnSameCoords,2, idsOfM1BNt);
2454               DAInt idsOfM1BN(idsOfM1BNt);
2455               mcIdType nCells=mAroundBN->getNumberOfCells(), nCellsDesc=mAroundBNDesc->getNumberOfCells();
2456               DAInt idsTouch=DataArrayIdType::New(); idsTouch->alloc(0,1);
2457               const mcIdType *revDescIBNP=revDescIBN->begin(), *revDescBNP=revDescBN->begin();
2458               for(const auto& v: *idsOfM1BN)
2459                 {
2460                   if (v >= nCellsDesc)    // Keep valid match only
2461                     continue;
2462                   mcIdType idx0 = revDescIBNP[v];
2463                   // Keep the two cells on either side of the face v of M1:
2464                   mcIdType c1=revDescBNP[idx0], c2=revDescBNP[idx0+1];
2465                   idsTouch->pushBackSilent(c1);  idsTouch->pushBackSilent(c2);
2466                 }
2467               //    3. Build complement
2468               DAInt idsTouchCompl = idsTouch->buildComplement(nCells);
2469               MCUMesh mAroundBNStrict = static_cast<MEDCouplingUMesh *>(mAroundBN->buildPartOfMySelf(idsTouchCompl->begin(), idsTouchCompl->end(), true));
2470               DAInt nod3 = mAroundBNStrict->computeFetchedNodeIds();
2471               DAInt inters = boundNodes->buildIntersection(nod3);
2472               fNodes1 = fNodes1->buildSubstraction(inters);  // reminder: fNodes1 represent nodes that need dupl.
2473             }
2474           notDup = xtrem->buildSubstraction(fNodes1);
2475         }
2476       else  // if (validIds-> ...)
2477         notDup = xtrem->buildSubstraction(fNodes);
2478     }
2479   else  // if (3D ...)
2480     notDup = xtrem->buildSubstraction(fNodes);
2481
2482   DAInt m1Nodes = otherDimM1OnSameCoords->computeFetchedNodeIds();
2483   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2484   return dupl.retn();
2485 }
2486
2487
2488 /*!
2489  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2490  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2491  * This method is part of the MEDFileUMesh::buildInnerBoundaryAlongM1Group() algorithm.
2492  * Given a set of nodes to duplicate, this method identifies which cells should have their connectivity modified
2493  * to produce the inner boundary. It is typically called after findNodesToDuplicate().
2494  *
2495  * \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.
2496  * \param [in] nodeIdsToDuplicateBg node ids needed to be duplicated, as returned by findNodesToDuplicate.
2497  * \param [in] nodeIdsToDuplicateEnd node ids needed to be duplicated, as returned by findNodesToDuplicate.
2498  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2499  * \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.
2500  *
2501  */
2502 void MEDCouplingUMesh::findCellsToRenumber(const MEDCouplingUMesh& otherDimM1OnSameCoords, const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd,
2503                                            DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2504 {
2505   using DAInt = MCAuto<DataArrayIdType>;
2506   using MCUMesh = MCAuto<MEDCouplingUMesh>;
2507
2508   checkFullyDefined();
2509   otherDimM1OnSameCoords.checkFullyDefined();
2510   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2511     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: meshes do not share the same coords array !");
2512   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2513     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: the mesh given in other parameter must have this->getMeshDimension()-1 !");
2514
2515   // Degenerated case - no nodes to duplicate
2516   if (nodeIdsToDuplicateBg == nodeIdsToDuplicateEnd)
2517     {
2518       cellIdsNeededToBeRenum = DataArrayIdType::New(); cellIdsNeededToBeRenum->alloc(0,1);
2519       cellIdsNotModified = DataArrayIdType::New(); cellIdsNotModified->alloc(0,1);
2520       return;
2521     }
2522
2523   // Compute cell IDs of the mesh with cells that touch the M1 group with a least one node:
2524   DAInt cellsAroundGroupLarge = getCellIdsLyingOnNodes(nodeIdsToDuplicateBg, nodeIdsToDuplicateEnd, false);  // false= take cell in, even if not all nodes are in dupl
2525   MCUMesh mAroundGrpLarge=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end(),true));
2526   mcIdType nCellsLarge=cellsAroundGroupLarge->getNumberOfTuples();
2527   DAInt descL=DataArrayIdType::New(),descIL=DataArrayIdType::New(),revDescL=DataArrayIdType::New(),revDescIL=DataArrayIdType::New();
2528   MCUMesh mArGrpLargeDesc=mAroundGrpLarge->buildDescendingConnectivity(descL,descIL,revDescL,revDescIL);
2529   const mcIdType *descILP=descIL->begin(), *descLP=descL->begin();
2530   DataArrayIdType *idsOfM1t;
2531   mArGrpLargeDesc->areCellsIncludedIn(&otherDimM1OnSameCoords,2, idsOfM1t);
2532   DAInt idsOfM1Large(idsOfM1t);
2533   mcIdType nL = mArGrpLargeDesc->getNumberOfCells();
2534
2535   // Computation of the neighbor information of the mesh WITH the crack (some neighbor links are removed):
2536   //     In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2537   //     of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2538   DAInt descLTrunc = descL->deepCopy(), descILTrunc = descIL->deepCopy();
2539   DataArrayIdType::RemoveIdsFromIndexedArrays(idsOfM1Large->begin(), idsOfM1Large->end(),descLTrunc,descILTrunc);
2540   DataArrayIdType *neight=0, *neighIt=0;
2541   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(descLTrunc,descILTrunc,revDescL,revDescIL, neight, neighIt);
2542   DAInt neighL(neight), neighIL(neighIt);
2543
2544   DAInt hitCellsLarge = DataArrayIdType::New(); hitCellsLarge->alloc(nCellsLarge,1);
2545   hitCellsLarge->fillWithValue(0);  // 0 : not hit, +1: one side of the crack, -1: other side of the crack,
2546   mcIdType* hitCellsLargeP = hitCellsLarge->rwBegin();
2547
2548   // Now loop on the faces of the M1 group and fill spread zones on either side of the crack:
2549   const mcIdType *revDescILP=revDescIL->begin(), *revDescLP=revDescL->begin();
2550   for(const auto& v: *idsOfM1Large)
2551     {
2552       if (v >= nL) continue;   // Keep valid match only - see doc of areCellsIncludedIn()
2553       mcIdType idx0 = revDescILP[v];
2554       // Retrieve the two cells on either side of the face v of M1:
2555       mcIdType c1=revDescLP[idx0], c2=revDescLP[idx0+1];
2556       std::map<mcIdType, mcIdType> toOther = {{c1, c2}, {c2, c1}};
2557       // Handle the spread zones on the two sides of the crack:
2558       for (const auto c: {c1, c2})
2559         {
2560           if (hitCellsLargeP[c]) continue;
2561           // Identify connex zone around this cell - if we find a value already assigned there, use it.
2562           mcIdType dnu;
2563           DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&c, &c+1, neighL,neighIL, -1, dnu);
2564           std::set<mcIdType> sv;
2565           for (const mcIdType& s: *spreadZone)
2566             if (hitCellsLargeP[s]) sv.insert(hitCellsLargeP[s]);
2567           if (sv.size() > 1)
2568             // Strange: we find in the same spread zone a +1 and -1 !
2569             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #0 - conflicting values - should not happen!");
2570           // If a valid value was found, use it:
2571           mcIdType val = sv.size()==1 ? *sv.begin() : 0;
2572           // Hopefully this does not conflict with an potential value on the other side:
2573           mcIdType other = toOther[c];
2574           if (hitCellsLargeP[other])
2575             {
2576               if(val && hitCellsLargeP[other] != -val)
2577                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: internal error #1 - conflicting values - should not happen!");;
2578               // We do not yet have a value, but other side has one. Use it!
2579               if(!val) val = -hitCellsLargeP[other];
2580             }
2581           // Cover first initialisation:
2582           if (!val) val = 1;
2583           // And finally, fill the current spread zone:
2584           for(const mcIdType& s: *spreadZone) hitCellsLargeP[s] = val;
2585         }
2586     }
2587
2588   DAInt cellsRet1 = hitCellsLarge->findIdsEqual(1);
2589   DAInt cellsRet2 = hitCellsLarge->findIdsEqual(-1);
2590
2591   if (cellsRet1->getNumberOfTuples() + cellsRet2->getNumberOfTuples() != cellsAroundGroupLarge->getNumberOfTuples())
2592     {
2593       DAInt nonHitCells = hitCellsLarge->findIdsEqual(0); // variable kept for debug ...
2594       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellsToRenumber: Some cells not hit - Internal error should not happen");
2595     }
2596   cellsRet1->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2597   cellsRet2->transformWithIndArr(cellsAroundGroupLarge->begin(),cellsAroundGroupLarge->end());
2598   //
2599   cellIdsNeededToBeRenum=cellsRet1.retn();
2600   cellIdsNotModified=cellsRet2.retn();
2601 }
2602
2603 /*!
2604  * This method operates a modification of the connectivity and coords in \b this.
2605  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2606  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2607  * 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
2608  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2609  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2610  *
2611  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2612  *
2613  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2614  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2615  */
2616 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2617 {
2618   mcIdType nbOfNodes=getNumberOfNodes();
2619   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2620   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2621 }
2622
2623 /*!
2624  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2625  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2626  *
2627  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2628  *
2629  * \sa renumberNodesInConn
2630  */
2631 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2632 {
2633   checkConnectivityFullyDefined();
2634   mcIdType *conn(getNodalConnectivity()->getPointer());
2635   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2636   mcIdType nbOfCells=getNumberOfCells();
2637   for(mcIdType i=0;i<nbOfCells;i++)
2638     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2639       {
2640         mcIdType& node=conn[iconn];
2641         if(node>=0)//avoid polyhedron separator
2642           {
2643             node+=offset;
2644           }
2645       }
2646   _nodal_connec->declareAsNew();
2647   updateTime();
2648 }
2649
2650 /*!
2651  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2652  *  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
2653  *  of a big mesh.
2654  */
2655 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2656 {
2657   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2658 }
2659
2660 /*!
2661  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2662  *  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
2663  *  of a big mesh.
2664  */
2665 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2666 {
2667   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2668 }
2669
2670 /*!
2671  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2672  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2673  * This method is a generalization of shiftNodeNumbersInConn().
2674  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2675  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2676  *         this->getNumberOfNodes(), in "Old to New" mode.
2677  *         See \ref numbering for more info on renumbering modes.
2678  *  \throw If the nodal connectivity of cells is not defined.
2679  *
2680  *  \if ENABLE_EXAMPLES
2681  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2682  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2683  *  \endif
2684  */
2685 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2686 {
2687   checkConnectivityFullyDefined();
2688   mcIdType *conn=getNodalConnectivity()->getPointer();
2689   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2690   mcIdType nbOfCells=getNumberOfCells();
2691   for(mcIdType i=0;i<nbOfCells;i++)
2692     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2693       {
2694         mcIdType& node=conn[iconn];
2695         if(node>=0)//avoid polyhedron separator
2696           {
2697             node=newNodeNumbersO2N[node];
2698           }
2699       }
2700   _nodal_connec->declareAsNew();
2701   updateTime();
2702 }
2703
2704 /*!
2705  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2706  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2707  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2708  *
2709  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2710  */
2711 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2712 {
2713   checkConnectivityFullyDefined();
2714   mcIdType *conn=getNodalConnectivity()->getPointer();
2715   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2716   mcIdType nbOfCells=getNumberOfCells();
2717   for(mcIdType i=0;i<nbOfCells;i++)
2718     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2719       {
2720         mcIdType& node=conn[iconn];
2721         if(node>=0)//avoid polyhedron separator
2722           {
2723             node+=delta;
2724           }
2725       }
2726   _nodal_connec->declareAsNew();
2727   updateTime();
2728 }
2729
2730 /*!
2731  * This method operates a modification of the connectivity in \b this.
2732  * 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.
2733  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2734  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2735  * 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
2736  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2737  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2738  *
2739  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2740  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2741  *
2742  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2743  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2744  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2745  */
2746 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2747 {
2748   checkConnectivityFullyDefined();
2749   std::map<mcIdType,mcIdType> m;
2750   mcIdType val=offset;
2751   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2752     m[*work]=val;
2753   mcIdType *conn=getNodalConnectivity()->getPointer();
2754   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2755   mcIdType nbOfCells=getNumberOfCells();
2756   for(mcIdType i=0;i<nbOfCells;i++)
2757     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2758       {
2759         mcIdType& node=conn[iconn];
2760         if(node>=0)//avoid polyhedron separator
2761           {
2762             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2763             if(it!=m.end())
2764               node=(*it).second;
2765           }
2766       }
2767   updateTime();
2768 }
2769
2770 /*!
2771  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2772  *
2773  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2774  * After the call of this method the number of cells remains the same as before.
2775  *
2776  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2777  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2778  * be strictly in [0;this->getNumberOfCells()).
2779  *
2780  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2781  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2782  * should be contained in[0;this->getNumberOfCells()).
2783  *
2784  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2785  * \param check whether to check content of old2NewBg
2786  */
2787 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2788 {
2789   checkConnectivityFullyDefined();
2790   mcIdType nbCells=getNumberOfCells();
2791   const mcIdType *array=old2NewBg;
2792   if(check)
2793     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2794   //
2795   const mcIdType *conn=_nodal_connec->getConstPointer();
2796   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2797   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2798   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2799   const mcIdType *n2oPtr=n2o->begin();
2800   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2801   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2802   newConn->copyStringInfoFrom(*_nodal_connec);
2803   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2804   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2805   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2806   //
2807   mcIdType *newC=newConn->getPointer();
2808   mcIdType *newCI=newConnI->getPointer();
2809   mcIdType loc=0;
2810   newCI[0]=loc;
2811   for(mcIdType i=0;i<nbCells;i++)
2812     {
2813       mcIdType pos=n2oPtr[i];
2814       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2815       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2816       loc+=nbOfElts;
2817       newCI[i+1]=loc;
2818     }
2819   //
2820   setConnectivity(newConn,newConnI);
2821   if(check)
2822     free(const_cast<mcIdType *>(array));
2823 }
2824
2825 /*!
2826  * Finds cells whose bounding boxes intersect a given bounding box.
2827  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2828  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2829  *         zMax (if in 3D).
2830  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2831  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2832  *         extent of the bounding box of cell to produce an addition to this bounding box.
2833  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2834  *         cells. The caller is to delete this array using decrRef() as it is no more
2835  *         needed.
2836  *  \throw If the coordinates array is not set.
2837  *  \throw If the nodal connectivity of cells is not defined.
2838  *
2839  *  \if ENABLE_EXAMPLES
2840  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2841  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2842  *  \endif
2843  */
2844 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2845 {
2846   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2847   if(getMeshDimension()==-1)
2848     {
2849       elems->pushBackSilent(0);
2850       return elems.retn();
2851     }
2852   int dim=getSpaceDimension();
2853   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2854   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2855   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2856   const double* coords = getCoords()->getConstPointer();
2857   mcIdType nbOfCells=getNumberOfCells();
2858   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2859     {
2860       for (int i=0; i<dim; i++)
2861         {
2862           elem_bb[i*2]=std::numeric_limits<double>::max();
2863           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2864         }
2865
2866       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2867         {
2868           mcIdType node= conn[inode];
2869           if(node>=0)//avoid polyhedron separator
2870             {
2871               for (int idim=0; idim<dim; idim++)
2872                 {
2873                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2874                     {
2875                       elem_bb[idim*2] = coords[node*dim+idim] ;
2876                     }
2877                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2878                     {
2879                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2880                     }
2881                 }
2882             }
2883         }
2884       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2885         elems->pushBackSilent(ielem);
2886     }
2887   return elems.retn();
2888 }
2889
2890 /*!
2891  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2892  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2893  * added in 'elems' parameter.
2894  */
2895 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2896 {
2897   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2898   if(getMeshDimension()==-1)
2899     {
2900       elems->pushBackSilent(0);
2901       return elems.retn();
2902     }
2903   int dim=getSpaceDimension();
2904   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2905   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2906   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2907   const double* coords = getCoords()->getConstPointer();
2908   mcIdType nbOfCells=getNumberOfCells();
2909   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2910     {
2911       for (int i=0; i<dim; i++)
2912         {
2913           elem_bb[i*2]=std::numeric_limits<double>::max();
2914           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2915         }
2916
2917       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2918         {
2919           mcIdType node= conn[inode];
2920           if(node>=0)//avoid polyhedron separator
2921             {
2922               for (int idim=0; idim<dim; idim++)
2923                 {
2924                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2925                     {
2926                       elem_bb[idim*2] = coords[node*dim+idim] ;
2927                     }
2928                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2929                     {
2930                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2931                     }
2932                 }
2933             }
2934         }
2935       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2936         elems->pushBackSilent(ielem);
2937     }
2938   return elems.retn();
2939 }
2940
2941 /*!
2942  * Returns a type of a cell by its id.
2943  *  \param [in] cellId - the id of the cell of interest.
2944  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2945  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2946  */
2947 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2948 {
2949   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2950   if(cellId<_nodal_connec_index->getNbOfElems()-1)
2951     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2952   else
2953     {
2954       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2955       throw INTERP_KERNEL::Exception(oss.str());
2956     }
2957 }
2958
2959 /*!
2960  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2961  * This method does not throw exception if geometric type \a type is not in \a this.
2962  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2963  * The coordinates array is not considered here.
2964  *
2965  * \param [in] type the geometric type
2966  * \return cell ids in this having geometric type \a type.
2967  */
2968 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2969 {
2970
2971   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2972   ret->alloc(0,1);
2973   checkConnectivityFullyDefined();
2974   mcIdType nbCells=getNumberOfCells();
2975   int mdim=getMeshDimension();
2976   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2977   if(mdim!=ToIdType(cm.getDimension()))
2978     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2979   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2980   const mcIdType *pt=_nodal_connec->getConstPointer();
2981   for(mcIdType i=0;i<nbCells;i++)
2982     {
2983       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2984         ret->pushBackSilent(i);
2985     }
2986   return ret.retn();
2987 }
2988
2989 /*!
2990  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2991  */
2992 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2993 {
2994   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2995   mcIdType nbOfCells(getNumberOfCells()),ret(0);
2996   for(mcIdType i=0;i<nbOfCells;i++)
2997     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2998       ret++;
2999   return ret;
3000 }
3001
3002 /*!
3003  * Returns the nodal connectivity of a given cell.
3004  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
3005  * all returned node ids can be used in getCoordinatesOfNode().
3006  *  \param [in] cellId - an id of the cell of interest.
3007  *  \param [in,out] conn - a vector where the node ids are appended. It is not
3008  *         cleared before the appending.
3009  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
3010  */
3011 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
3012 {
3013   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
3014   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
3015     if(*w>=0)
3016       conn.push_back(*w);
3017 }
3018
3019 std::string MEDCouplingUMesh::simpleRepr() const
3020 {
3021   static const char msg0[]="No coordinates specified !";
3022   std::ostringstream ret;
3023   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3024   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3025   int tmpp1,tmpp2;
3026   double tt=getTime(tmpp1,tmpp2);
3027   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3028   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3029   if(_mesh_dim>=-1)
3030     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3031   else
3032     { ret << " Mesh dimension has not been set or is invalid !"; }
3033   if(_coords!=0)
3034     {
3035       const int spaceDim=getSpaceDimension();
3036       ret << spaceDim << "\nInfo attached on space dimension : ";
3037       for(int i=0;i<spaceDim;i++)
3038         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3039       ret << "\n";
3040     }
3041   else
3042     ret << msg0 << "\n";
3043   ret << "Number of nodes : ";
3044   if(_coords!=0)
3045     ret << getNumberOfNodes() << "\n";
3046   else
3047     ret << msg0 << "\n";
3048   ret << "Number of cells : ";
3049   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3050     ret << getNumberOfCells() << "\n";
3051   else
3052     ret << "No connectivity specified !" << "\n";
3053   ret << "Cell types present : ";
3054   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3055     {
3056       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3057       ret << cm.getRepr() << " ";
3058     }
3059   ret << "\n";
3060   return ret.str();
3061 }
3062
3063 std::string MEDCouplingUMesh::advancedRepr() const
3064 {
3065   std::ostringstream ret;
3066   ret << simpleRepr();
3067   ret << "\nCoordinates array : \n___________________\n\n";
3068   if(_coords)
3069     _coords->reprWithoutNameStream(ret);
3070   else
3071     ret << "No array set !\n";
3072   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3073   reprConnectivityOfThisLL(ret);
3074   return ret.str();
3075 }
3076
3077 /*!
3078  * This method returns a C++ code that is a dump of \a this.
3079  * This method will throw if this is not fully defined.
3080  */
3081 std::string MEDCouplingUMesh::cppRepr() const
3082 {
3083   static const char coordsName[]="coords";
3084   static const char connName[]="conn";
3085   static const char connIName[]="connI";
3086   checkFullyDefined();
3087   std::ostringstream ret; ret << "// coordinates" << std::endl;
3088   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3089   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3090   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3091   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3092   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3093   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3094   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3095   return ret.str();
3096 }
3097
3098 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3099 {
3100   std::ostringstream ret;
3101   reprConnectivityOfThisLL(ret);
3102   return ret.str();
3103 }
3104
3105 /*!
3106  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
3107  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3108  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3109  * some algos).
3110  *
3111  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3112  * 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
3113  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3114  */
3115 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
3116 {
3117   int mdim=getMeshDimension();
3118   if(mdim<0)
3119     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3120   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3121   MCAuto<DataArrayIdType> tmp1,tmp2;
3122   bool needToCpyCT=true;
3123   if(!_nodal_connec)
3124     {
3125       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
3126       needToCpyCT=false;
3127     }
3128   else
3129     {
3130       tmp1=_nodal_connec;
3131       tmp1->incrRef();
3132     }
3133   if(!_nodal_connec_index)
3134     {
3135       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3136       needToCpyCT=false;
3137     }
3138   else
3139     {
3140       tmp2=_nodal_connec_index;
3141       tmp2->incrRef();
3142     }
3143   ret->setConnectivity(tmp1,tmp2,false);
3144   if(needToCpyCT)
3145     ret->_types=_types;
3146   if(!_coords)
3147     {
3148       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3149       ret->setCoords(coords);
3150     }
3151   else
3152     ret->setCoords(_coords);
3153   return ret.retn();
3154 }
3155
3156 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
3157 {
3158   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
3159   const mcIdType *pt=_nodal_connec->getConstPointer();
3160   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3161     return ptI[cellId+1]-ptI[cellId]-1;
3162   else
3163     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind(std::not_equal_to<mcIdType>(),std::placeholders::_1,-1)));
3164 }
3165
3166 /*!
3167  * Returns types of cells of the specified part of \a this mesh.
3168  * This method avoids computing sub-mesh explicitly to get its types.
3169  *  \param [in] begin - an array of cell ids of interest.
3170  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3171  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3172  *         describing the cell types.
3173  *  \throw If the coordinates array is not set.
3174  *  \throw If the nodal connectivity of cells is not defined.
3175  *  \sa getAllGeoTypes()
3176  */
3177 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3178 {
3179   checkFullyDefined();
3180   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3181   const mcIdType *conn=_nodal_connec->getConstPointer();
3182   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3183   for(const mcIdType *w=begin;w!=end;w++)
3184     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3185   return ret;
3186 }
3187
3188 /*!
3189  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3190  * Optionally updates
3191  * a set of types of cells constituting \a this mesh.
3192  * This method is for advanced users having prepared their connectivity before. For
3193  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3194  *  \param [in] conn - the nodal connectivity array.
3195  *  \param [in] connIndex - the nodal connectivity index array.
3196  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3197  *         mesh is updated.
3198  */
3199 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3200 {
3201   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3202   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3203   if(isComputingTypes)
3204     computeTypes();
3205   declareAsNew();
3206 }
3207
3208 /*!
3209  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3210  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3211  */
3212 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3213     _nodal_connec(0),_nodal_connec_index(0),
3214     _types(other._types)
3215 {
3216   if(other._nodal_connec)
3217     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3218   if(other._nodal_connec_index)
3219     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3220 }
3221
3222 MEDCouplingUMesh::~MEDCouplingUMesh()
3223 {
3224   if(_nodal_connec)
3225     _nodal_connec->decrRef();
3226   if(_nodal_connec_index)
3227     _nodal_connec_index->decrRef();
3228 }
3229
3230 /*!
3231  * Recomputes a set of cell types of \a this mesh. For more info see
3232  * \ref MEDCouplingUMeshNodalConnectivity.
3233  */
3234 void MEDCouplingUMesh::computeTypes()
3235 {
3236   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3237 }
3238
3239
3240 /*!
3241  * Returns a number of cells constituting \a this mesh.
3242  *  \return mcIdType - the number of cells in \a this mesh.
3243  *  \throw If the nodal connectivity of cells is not defined.
3244  */
3245 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3246 {
3247   if(_nodal_connec_index)
3248     return _nodal_connec_index->getNumberOfTuples()-1;
3249   else
3250     if(_mesh_dim==-1)
3251       return 1;
3252     else
3253       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3254 }
3255
3256 /*!
3257  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3258  * mesh. For more info see \ref meshes.
3259  *  \return int - the dimension of \a this mesh.
3260  *  \throw If the mesh dimension is not defined using setMeshDimension().
3261  */
3262 int MEDCouplingUMesh::getMeshDimension() const
3263 {
3264   if(_mesh_dim<-1)
3265     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3266   return _mesh_dim;
3267 }
3268
3269 /*!
3270  * Returns a length of the nodal connectivity array.
3271  * This method is for test reason. Normally the integer returned is not useable by
3272  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3273  *  \return mcIdType - the length of the nodal connectivity array.
3274  */
3275 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3276 {
3277   return _nodal_connec->getNbOfElems();
3278 }
3279
3280 /*!
3281  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3282  */
3283 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3284 {
3285   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3286   tinyInfo.push_back(ToIdType(getMeshDimension()));
3287   tinyInfo.push_back(getNumberOfCells());
3288   if(_nodal_connec)
3289     tinyInfo.push_back(getNodalConnectivityArrayLen());
3290   else
3291     tinyInfo.push_back(-1);
3292 }
3293
3294 /*!
3295  * First step of unserialization process.
3296  */
3297 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3298 {
3299   return tinyInfo[6]<=0;
3300 }
3301
3302 /*!
3303  * Second step of serialization process.
3304  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3305  * \param a1 DataArrayDouble
3306  * \param a2 DataArrayDouble
3307  * \param littleStrings string vector
3308  */
3309 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3310 {
3311   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3312   if(tinyInfo[5]!=-1)
3313     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3314 }
3315
3316 /*!
3317  * Third and final step of serialization process.
3318  */
3319 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3320 {
3321   MEDCouplingPointSet::serialize(a1,a2);
3322   if(getMeshDimension()>-1)
3323     {
3324       a1=DataArrayIdType::New();
3325       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3326       mcIdType *ptA1=a1->getPointer();
3327       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3328       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3329       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3330       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3331     }
3332   else
3333     a1=0;
3334 }
3335
3336 /*!
3337  * Second and final unserialization process.
3338  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3339  */
3340 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3341 {
3342   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3343   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3344   if(tinyInfo[7]!=-1)
3345     {
3346       // Connectivity
3347       const mcIdType *recvBuffer=a1->getConstPointer();
3348       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3349       myConnecIndex->alloc(tinyInfo[6]+1,1);
3350       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3351       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3352       myConnec->alloc(tinyInfo[7],1);
3353       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3354       setConnectivity(myConnec, myConnecIndex);
3355     }
3356 }
3357
3358
3359
3360 /*!
3361  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3362  * mesh.<br>
3363  * For 1D cells, the returned field contains lengths.<br>
3364  * For 2D cells, the returned field contains areas.<br>
3365  * For 3D cells, the returned field contains volumes.
3366  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3367  *         orientation, i.e. the volume is always positive.
3368  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3369  *         and one time . The caller is to delete this field using decrRef() as it is no
3370  *         more needed.
3371  */
3372 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3373 {
3374   std::string name="MeasureOfMesh_";
3375   name+=getName();
3376   mcIdType nbelem=getNumberOfCells();
3377   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3378   field->setName(name);
3379   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3380   array->alloc(nbelem,1);
3381   double *area_vol=array->getPointer();
3382   field->setArray(array) ; array=0;
3383   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3384   field->synchronizeTimeWithMesh();
3385   if(getMeshDimension()!=-1)
3386     {
3387       mcIdType ipt;
3388       INTERP_KERNEL::NormalizedCellType type;
3389       int dim_space=getSpaceDimension();
3390       const double *coords=getCoords()->getConstPointer();
3391       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3392       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3393       for(mcIdType iel=0;iel<nbelem;iel++)
3394         {
3395           ipt=connec_index[iel];
3396           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3397           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);
3398         }
3399       if(isAbs)
3400         std::transform(area_vol,area_vol+nbelem,area_vol,[](double c){return fabs(c);});
3401     }
3402   else
3403     {
3404       area_vol[0]=std::numeric_limits<double>::max();
3405     }
3406   return field.retn();
3407 }
3408
3409 /*!
3410  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3411  * mesh.<br>
3412  * For 1D cells, the returned array contains lengths.<br>
3413  * For 2D cells, the returned array contains areas.<br>
3414  * For 3D cells, the returned array contains volumes.
3415  * This method avoids building explicitly a part of \a this mesh to perform the work.
3416  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3417  *         orientation, i.e. the volume is always positive.
3418  *  \param [in] begin - an array of cell ids of interest.
3419  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3420  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3421  *          delete this array using decrRef() as it is no more needed.
3422  *
3423  *  \if ENABLE_EXAMPLES
3424  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3425  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3426  *  \endif
3427  *  \sa getMeasureField()
3428  */
3429 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3430 {
3431   std::string name="PartMeasureOfMesh_";
3432   name+=getName();
3433   std::size_t nbelem=std::distance(begin,end);
3434   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3435   array->setName(name);
3436   array->alloc(nbelem,1);
3437   double *area_vol=array->getPointer();
3438   if(getMeshDimension()!=-1)
3439     {
3440       mcIdType ipt;
3441       INTERP_KERNEL::NormalizedCellType type;
3442       int dim_space=getSpaceDimension();
3443       const double *coords=getCoords()->getConstPointer();
3444       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3445       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3446       for(const mcIdType *iel=begin;iel!=end;iel++)
3447         {
3448           ipt=connec_index[*iel];
3449           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3450           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3451         }
3452       if(isAbs)
3453         std::transform(array->getPointer(),area_vol,array->getPointer(),[](double c){return fabs(c);});
3454     }
3455   else
3456     {
3457       area_vol[0]=std::numeric_limits<double>::max();
3458     }
3459   return array.retn();
3460 }
3461
3462 /*!
3463  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3464  * \a this one. The returned field contains the dual cell volume for each corresponding
3465  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3466  *  the dual mesh in P1 sens of \a this.<br>
3467  * For 1D cells, the returned field contains lengths.<br>
3468  * For 2D cells, the returned field contains areas.<br>
3469  * For 3D cells, the returned field contains volumes.
3470  * This method is useful to check "P1*" conservative interpolators.
3471  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3472  *         orientation, i.e. the volume is always positive.
3473  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3474  *          nodes and one time. The caller is to delete this array using decrRef() as
3475  *          it is no more needed.
3476  */
3477 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3478 {
3479   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3480   std::string name="MeasureOnNodeOfMesh_";
3481   name+=getName();
3482   mcIdType nbNodes=getNumberOfNodes();
3483   MCAuto<DataArrayDouble> nnpc;
3484   {
3485     MCAuto<DataArrayIdType> tmp2(computeNbOfNodesPerCell());
3486     nnpc=tmp2->convertToDblArr();
3487   }
3488   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3489   const double *nnpcPtr(nnpc->begin());
3490   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3491   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3492   array->alloc(nbNodes,1);
3493   double *valsToFill=array->getPointer();
3494   std::fill(valsToFill,valsToFill+nbNodes,0.);
3495   const double *values=tmp->getArray()->getConstPointer();
3496   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3497   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3498   getReverseNodalConnectivity(da,daInd);
3499   const mcIdType *daPtr=da->getConstPointer();
3500   const mcIdType *daIPtr=daInd->getConstPointer();
3501   for(mcIdType i=0;i<nbNodes;i++)
3502     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3503       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3504   ret->setMesh(this);
3505   ret->setArray(array);
3506   return ret.retn();
3507 }
3508
3509 /*!
3510  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3511  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3512  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3513  * and are normalized.
3514  * <br> \a this can be either
3515  * - a  2D mesh in 2D or 3D space or
3516  * - an 1D mesh in 2D space.
3517  *
3518  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3519  *          cells and one time. The caller is to delete this field using decrRef() as
3520  *          it is no more needed.
3521  *  \throw If the nodal connectivity of cells is not defined.
3522  *  \throw If the coordinates array is not set.
3523  *  \throw If the mesh dimension is not set.
3524  *  \throw If the mesh and space dimension is not as specified above.
3525  */
3526 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3527 {
3528   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3529     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3530   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3531   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3532   mcIdType nbOfCells=getNumberOfCells();
3533   int nbComp=getMeshDimension()+1;
3534   array->alloc(nbOfCells,nbComp);
3535   double *vals=array->getPointer();
3536   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3537   const mcIdType *conn=_nodal_connec->getConstPointer();
3538   const double *coords=_coords->getConstPointer();
3539   if(getMeshDimension()==2)
3540     {
3541       if(getSpaceDimension()==3)
3542         {
3543           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3544           const double *locPtr=loc->getConstPointer();
3545           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3546             {
3547               mcIdType offset=connI[i];
3548               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3549               double n=INTERP_KERNEL::norm<3>(vals);
3550               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3551             }
3552         }
3553       else
3554         {
3555           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3556           const double *isAbsPtr=isAbs->getArray()->begin();
3557           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3558             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3559         }
3560     }
3561   else//meshdimension==1
3562     {
3563       double tmp[2];
3564       for(mcIdType i=0;i<nbOfCells;i++)
3565         {
3566           mcIdType offset=connI[i];
3567           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3568           double n=INTERP_KERNEL::norm<2>(tmp);
3569           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3570           *vals++=-tmp[1];
3571           *vals++=tmp[0];
3572         }
3573     }
3574   ret->setArray(array);
3575   ret->setMesh(this);
3576   ret->synchronizeTimeWithSupport();
3577   return ret.retn();
3578 }
3579
3580 /*!
3581  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3582  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3583  * and are normalized.
3584  * <br> \a this can be either
3585  * - a  2D mesh in 2D or 3D space or
3586  * - an 1D mesh in 2D space.
3587  *
3588  * This method avoids building explicitly a part of \a this mesh to perform the work.
3589  *  \param [in] begin - an array of cell ids of interest.
3590  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3591  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3592  *          cells and one time. The caller is to delete this field using decrRef() as
3593  *          it is no more needed.
3594  *  \throw If the nodal connectivity of cells is not defined.
3595  *  \throw If the coordinates array is not set.
3596  *  \throw If the mesh dimension is not set.
3597  *  \throw If the mesh and space dimension is not as specified above.
3598  *  \sa buildOrthogonalField()
3599  *
3600  *  \if ENABLE_EXAMPLES
3601  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3602  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3603  *  \endif
3604  */
3605 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3606 {
3607   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3608     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3609   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3610   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3611   std::size_t nbelems=std::distance(begin,end);
3612   int nbComp=getMeshDimension()+1;
3613   array->alloc(nbelems,nbComp);
3614   double *vals=array->getPointer();
3615   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3616   const mcIdType *conn=_nodal_connec->getConstPointer();
3617   const double *coords=_coords->getConstPointer();
3618   if(getMeshDimension()==2)
3619     {
3620       if(getSpaceDimension()==3)
3621         {
3622           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3623           const double *locPtr=loc->getConstPointer();
3624           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3625             {
3626               mcIdType offset=connI[*i];
3627               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3628               double n=INTERP_KERNEL::norm<3>(vals);
3629               std::transform(vals,vals+3,vals,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3630             }
3631         }
3632       else
3633         {
3634           for(std::size_t i=0;i<nbelems;i++)
3635             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3636         }
3637     }
3638   else//meshdimension==1
3639     {
3640       double tmp[2];
3641       for(const mcIdType *i=begin;i!=end;i++)
3642         {
3643           mcIdType offset=connI[*i];
3644           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3645           double n=INTERP_KERNEL::norm<2>(tmp);
3646           std::transform(tmp,tmp+2,tmp,std::bind(std::multiplies<double>(),std::placeholders::_1,1./n));
3647           *vals++=-tmp[1];
3648           *vals++=tmp[0];
3649         }
3650     }
3651   ret->setArray(array);
3652   ret->setMesh(this);
3653   ret->synchronizeTimeWithSupport();
3654   return ret.retn();
3655 }
3656
3657 /*!
3658  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3659  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3660  * and are \b not normalized.
3661  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3662  *          cells and one time. The caller is to delete this field using decrRef() as
3663  *          it is no more needed.
3664  *  \throw If the nodal connectivity of cells is not defined.
3665  *  \throw If the coordinates array is not set.
3666  *  \throw If \a this->getMeshDimension() != 1.
3667  *  \throw If \a this mesh includes cells of type other than SEG2.
3668  */
3669 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3670 {
3671   if(getMeshDimension()!=1)
3672     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3673   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3674     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3675   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3676   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3677   mcIdType nbOfCells=getNumberOfCells();
3678   int spaceDim=getSpaceDimension();
3679   array->alloc(nbOfCells,spaceDim);
3680   double *pt=array->getPointer();
3681   const double *coo=getCoords()->getConstPointer();
3682   std::vector<mcIdType> conn;
3683   conn.reserve(2);
3684   for(mcIdType i=0;i<nbOfCells;i++)
3685     {
3686       conn.resize(0);
3687       getNodeIdsOfCell(i,conn);
3688       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3689     }
3690   ret->setArray(array);
3691   ret->setMesh(this);
3692   ret->synchronizeTimeWithSupport();
3693   return ret.retn();
3694 }
3695
3696 /*!
3697  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3698  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3699  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3700  * from. If a result face is shared by two 3D cells, then the face in included twice in
3701  * the result mesh.
3702  *  \param [in] origin - 3 components of a point defining location of the plane.
3703  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3704  *         must be greater than 1e-6.
3705  *  \param [in] eps - half-thickness of the plane.
3706  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3707  *         producing correspondent 2D cells. The caller is to delete this array
3708  *         using decrRef() as it is no more needed.
3709  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3710  *         not share the node coordinates array with \a this mesh. The caller is to
3711  *         delete this mesh using decrRef() as it is no more needed.
3712  *  \throw If the coordinates array is not set.
3713  *  \throw If the nodal connectivity of cells is not defined.
3714  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3715  *  \throw If magnitude of \a vec is less than 1e-6.
3716  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3717  *  \throw If \a this includes quadratic cells.
3718  */
3719 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3720 {
3721   checkFullyDefined();
3722   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3723     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3724   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3725   if(candidates->empty())
3726     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3727   std::vector<mcIdType> nodes;
3728   DataArrayIdType *cellIds1D=0;
3729   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3730   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3731   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3732   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3733   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3734   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3735   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3736   revDesc2=0; revDescIndx2=0;
3737   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3738   revDesc1=0; revDescIndx1=0;
3739   //Marking all 1D cells that contained at least one node located on the plane
3740   //the intersection between those cells and the plane, which consist of the nodes previously tagged, thus don't need to be computed afterwards
3741   //(if said intersection is computed in MEDCouplingUMesh::split3DCurveWithPlane, then we might create additional nodes
3742   //due to accuracy errors when the needed nodes already exist)
3743   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),false,cellIds1D);
3744   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3745   //
3746   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3747   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3748     cut3DCurve[*it]=-1;
3749   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3750   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3751   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3752                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3753                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3754   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3755   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3756   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3757   if(cellIds2->empty())
3758     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3759   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3760   ret->setCoords(mDesc1->getCoords());
3761   ret->setConnectivity(conn,connI,true);
3762   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3763   return ret.retn();
3764 }
3765
3766 /*!
3767  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3768 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
3769 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3770 the result mesh.
3771  *  \param [in] origin - 3 components of a point defining location of the plane.
3772  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3773  *         must be greater than 1e-6.
3774  *  \param [in] eps - half-thickness of the plane.
3775  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3776  *         producing correspondent segments. The caller is to delete this array
3777  *         using decrRef() as it is no more needed.
3778  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3779  *         mesh in 3D space. This mesh does not share the node coordinates array with
3780  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3781  *         no more needed.
3782  *  \throw If the coordinates array is not set.
3783  *  \throw If the nodal connectivity of cells is not defined.
3784  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3785  *  \throw If magnitude of \a vec is less than 1e-6.
3786  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3787  *  \throw If \a this includes quadratic cells.
3788  */
3789 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3790 {
3791   checkFullyDefined();
3792   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3793     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3794   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3795   if(candidates->empty())
3796     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3797   std::vector<mcIdType> nodes;
3798   DataArrayIdType *cellIds1D(0);
3799   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3800   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3801   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3802   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3803   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3804   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3805   //
3806   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3807   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3808     cut3DCurve[*it]=-1;
3809   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3810   mcIdType ncellsSub=subMesh->getNumberOfCells();
3811   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3812   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3813                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3814                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3815   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3816   conn->alloc(0,1);
3817   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3818   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3819   for(mcIdType i=0;i<ncellsSub;i++)
3820     {
3821       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3822         {
3823           if(cut3DSurf[i].first!=-2)
3824             {
3825               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3826               connI->pushBackSilent(conn->getNumberOfTuples());
3827               cellIds2->pushBackSilent(i);
3828             }
3829           else
3830             {
3831               mcIdType cellId3DSurf=cut3DSurf[i].second;
3832               mcIdType offset=nodalI[cellId3DSurf]+1;
3833               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3834               for(mcIdType j=0;j<nbOfEdges;j++)
3835                 {
3836                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3837                   connI->pushBackSilent(conn->getNumberOfTuples());
3838                   cellIds2->pushBackSilent(cellId3DSurf);
3839                 }
3840             }
3841         }
3842     }
3843   if(cellIds2->empty())
3844     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3845   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3846   ret->setCoords(mDesc1->getCoords());
3847   ret->setConnectivity(conn,connI,true);
3848   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3849   return ret.retn();
3850 }
3851
3852 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3853 {
3854   checkFullyDefined();
3855   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3856     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3857   if(getNumberOfCells()!=1)
3858     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3859   //
3860   std::vector<mcIdType> nodes;
3861   findNodesOnPlane(origin,vec,eps,nodes);
3862   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());
3863   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3864   revDesc2=0; revDescIndx2=0;
3865   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3866   revDesc1=0; revDescIndx1=0;
3867   DataArrayIdType *cellIds1D(0);
3868   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3869   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3870   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3871   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3872     cut3DCurve[*it]=-1;
3873   bool sameNbNodes;
3874   {
3875     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3876     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3877     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3878   }
3879   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3880   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3881                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3882                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3883   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3884   connI->pushBackSilent(0); conn->alloc(0,1);
3885   {
3886     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3887     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3888     if(cellIds2->empty())
3889       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3890   }
3891   std::vector<std::vector<mcIdType> > res;
3892   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3893   std::size_t sz(res.size());
3894   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3895     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3896   for(std::size_t i=0;i<sz;i++)
3897     {
3898       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3899       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3900       connI->pushBackSilent(conn->getNumberOfTuples());
3901     }
3902   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3903   ret->setCoords(mDesc1->getCoords());
3904   ret->setConnectivity(conn,connI,true);
3905   mcIdType nbCellsRet(ret->getNumberOfCells());
3906   //
3907   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3908   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3909   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3910   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3911   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3912   MCAuto<DataArrayDouble> occm;
3913   {
3914     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3915     occm=DataArrayDouble::Substract(ccm,pt);
3916   }
3917   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3918   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);
3919   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3920   //
3921   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3922   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3923   ret2->setCoords(mDesc1->getCoords());
3924   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3925   conn2I->pushBackSilent(0); conn2->alloc(0,1);
3926   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3927   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3928   if(dott->getIJ(0,0)>0)
3929     {
3930       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3931       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3932     }
3933   else
3934     {
3935       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3936       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3937     }
3938   for(mcIdType i=1;i<nbCellsRet;i++)
3939     {
3940       if(dott2->getIJ(i,0)<0)
3941         {
3942           if(ciPtr[i+1]-ciPtr[i]>=4)
3943             {
3944               cell0.push_back(-1);
3945               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3946             }
3947         }
3948       else
3949         {
3950           if(ciPtr[i+1]-ciPtr[i]>=4)
3951             {
3952               cell1.push_back(-1);
3953               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3954             }
3955         }
3956     }
3957   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3958   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3959   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3960   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3961   ret2->setConnectivity(conn2,conn2I,true);
3962   ret2->checkConsistencyLight();
3963   ret2->orientCorrectlyPolyhedrons();
3964   return ret2;
3965 }
3966
3967 /*!
3968  * Finds cells whose bounding boxes intersect a given plane.
3969  *  \param [in] origin - 3 components of a point defining location of the plane.
3970  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3971  *         must be greater than 1e-6.
3972  *  \param [in] eps - half-thickness of the plane.
3973  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3974  *         cells. The caller is to delete this array using decrRef() as it is no more
3975  *         needed.
3976  *  \throw If the coordinates array is not set.
3977  *  \throw If the nodal connectivity of cells is not defined.
3978  *  \throw If \a this->getSpaceDimension() != 3.
3979  *  \throw If magnitude of \a vec is less than 1e-6.
3980  *  \sa buildSlice3D()
3981  */
3982 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3983 {
3984   checkFullyDefined();
3985   if(getSpaceDimension()!=3)
3986     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3987   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3988   if(normm<1e-6)
3989     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3990   double vec2[3];
3991   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3992   double angle=acos(vec[2]/normm);
3993   MCAuto<DataArrayIdType> cellIds;
3994   double bbox[6];
3995   if(angle>eps)
3996     {
3997       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3998       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3999       if(normm2/normm>1e-6)
4000         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
4001       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
4002       mw->setCoords(coo);
4003       mw->getBoundingBox(bbox);
4004       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4005       cellIds=mw->getCellsInBoundingBox(bbox,eps);
4006     }
4007   else
4008     {
4009       getBoundingBox(bbox);
4010       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
4011       cellIds=getCellsInBoundingBox(bbox,eps);
4012     }
4013   return cellIds.retn();
4014 }
4015
4016 /*!
4017  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4018  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4019  * No consideration of coordinate is done by this method.
4020  * 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)
4021  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
4022  */
4023 bool MEDCouplingUMesh::isContiguous1D() const
4024 {
4025   if(getMeshDimension()!=1)
4026     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4027   mcIdType nbCells=getNumberOfCells();
4028   if(nbCells<1)
4029     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4030   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
4031   mcIdType ref=conn[connI[0]+2];
4032   for(mcIdType i=1;i<nbCells;i++)
4033     {
4034       if(conn[connI[i]+1]!=ref)
4035         return false;
4036       ref=conn[connI[i]+2];
4037     }
4038   return true;
4039 }
4040
4041 /*!
4042  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4043  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4044  * \param pt reference point of the line
4045  * \param v normalized director vector of the line
4046  * \param eps max precision before throwing an exception
4047  * \param res output of size this->getNumberOfCells
4048  */
4049 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4050 {
4051   if(getMeshDimension()!=1)
4052     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4053   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4054     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4055   if(getSpaceDimension()!=3)
4056     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4057   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4058   const double *fPtr=f->getArray()->getConstPointer();
4059   double tmp[3];
4060   for(mcIdType i=0;i<getNumberOfCells();i++)
4061     {
4062       const double *tmp1=fPtr+3*i;
4063       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4064       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4065       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4066       double n1=INTERP_KERNEL::norm<3>(tmp);
4067       n1/=INTERP_KERNEL::norm<3>(tmp1);
4068       if(n1>eps)
4069         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4070     }
4071   const double *coo=getCoords()->getConstPointer();
4072   for(mcIdType i=0;i<getNumberOfNodes();i++)
4073     {
4074       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4075       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4076       res[i]=std::accumulate(tmp,tmp+3,0.);
4077     }
4078 }
4079
4080 /*!
4081  * 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.
4082  * \a this is expected to be a mesh so that its space dimension is equal to its
4083  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4084  * 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).
4085  *
4086  * 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
4087  * 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).
4088  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4089  *
4090  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4091  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4092  *
4093  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4094  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4095  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4096  * \return the positive value of the distance.
4097  * \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
4098  * dimension - 1.
4099  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4100  */
4101 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
4102 {
4103   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4104   if(meshDim!=spaceDim-1)
4105     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4106   if(meshDim!=2 && meshDim!=1)
4107     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4108   checkFullyDefined();
4109   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
4110     { 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()); }
4111   DataArrayIdType *ret1=0;
4112   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
4113   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4114   MCAuto<DataArrayIdType> ret1Safe(ret1);
4115   cellId=*ret1Safe->begin();
4116   return *ret0->begin();
4117 }
4118
4119 /*!
4120  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4121  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
4122  * 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
4123  * 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).
4124  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4125  *
4126  * \a this is expected to be a mesh so that its space dimension is equal to its
4127  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4128  * 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).
4129  *
4130  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4131  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4132  *
4133  * \param [in] pts the list of points in which each tuple represents a point
4134  * \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.
4135  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4136  * \throw if number of components of \a pts is not equal to the space dimension.
4137  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4138  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4139  */
4140 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
4141 {
4142   if(!pts)
4143     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4144   pts->checkAllocated();
4145   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4146   if(meshDim!=spaceDim-1)
4147     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4148   if(meshDim!=2 && meshDim!=1)
4149     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4150   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
4151     {
4152       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4153       throw INTERP_KERNEL::Exception(oss.str());
4154     }
4155   checkFullyDefined();
4156   mcIdType nbCells=getNumberOfCells();
4157   if(nbCells==0)
4158     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4159   mcIdType nbOfPts=pts->getNumberOfTuples();
4160   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4161   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
4162   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4163   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4164   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4165   const double *bbox(bboxArr->begin());
4166   switch(spaceDim)
4167   {
4168     case 3:
4169       {
4170         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4171         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4172           {
4173             double x=std::numeric_limits<double>::max();
4174             std::vector<mcIdType> elems;
4175             myTree.getMinDistanceOfMax(ptsPtr,x);
4176             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4177             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4178           }
4179         break;
4180       }
4181     case 2:
4182       {
4183         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4184         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4185           {
4186             double x=std::numeric_limits<double>::max();
4187             std::vector<mcIdType> elems;
4188             myTree.getMinDistanceOfMax(ptsPtr,x);
4189             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4190             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4191           }
4192         break;
4193       }
4194     default:
4195       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4196   }
4197   cellIds=ret1.retn();
4198   return ret0.retn();
4199 }
4200
4201 /// @cond INTERNAL
4202
4203 /// @endcond
4204
4205 /*!
4206  * Finds cells in contact with a ball (i.e. a point with precision).
4207  * 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.
4208  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4209  *
4210  * \warning This method is suitable if the caller intends to evaluate only one
4211  *          point, for more points getCellsContainingPoints() is recommended as it is
4212  *          faster.
4213  *  \param [in] pos - array of coordinates of the ball central point.
4214  *  \param [in] eps - ball radius.
4215  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4216  *         if there are no such cells.
4217  *  \throw If the coordinates array is not set.
4218  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4219  */
4220 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4221 {
4222   std::vector<mcIdType> elts;
4223   getCellsContainingPoint(pos,eps,elts);
4224   if(elts.empty())
4225     return -1;
4226   return elts.front();
4227 }
4228
4229 /*!
4230  * Finds cells in contact with a ball (i.e. a point with precision).
4231  * 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.
4232  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4233  * \warning This method is suitable if the caller intends to evaluate only one
4234  *          point, for more points getCellsContainingPoints() is recommended as it is
4235  *          faster.
4236  *  \param [in] pos - array of coordinates of the ball central point.
4237  *  \param [in] eps - ball radius.
4238  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4239  *         before inserting ids.
4240  *  \throw If the coordinates array is not set.
4241  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4242  *
4243  *  \if ENABLE_EXAMPLES
4244  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4245  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4246  *  \endif
4247  */
4248 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4249 {
4250   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4251   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4252   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4253 }
4254
4255 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4256                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4257                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4258 {
4259   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4260   if(spaceDim==3)
4261     {
4262       if(mDim==3)
4263         {
4264           const double *coords=_coords->getConstPointer();
4265           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4266         }
4267       else
4268         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4269     }
4270   else if(spaceDim==2)
4271     {
4272       if(mDim==2)
4273         {
4274           const double *coords=_coords->getConstPointer();
4275           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4276         }
4277       else
4278         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4279     }
4280   else if(spaceDim==1)
4281     {
4282       if(mDim==1)
4283         {
4284           const double *coords=_coords->getConstPointer();
4285           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4286         }
4287       else
4288         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4289     }
4290   else
4291     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4292 }
4293
4294 /*!
4295  * Finds cells in contact with several balls (i.e. points with precision).
4296  * This method is an extension of getCellContainingPoint() and
4297  * getCellsContainingPoint() for the case of multiple points.
4298  * 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.
4299  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4300  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4301  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4302  *         this->getSpaceDimension() * \a nbOfPoints
4303  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4304  *  \param [in] eps - radius of balls (i.e. the precision).
4305  *  \param [out] elts - vector returning ids of found cells.
4306  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4307  *         dividing cell ids in \a elts into groups each referring to one
4308  *         point. Its every element (except the last one) is an index pointing to the
4309  *         first id of a group of cells. For example cells in contact with the *i*-th
4310  *         point are described by following range of indices:
4311  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4312  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4313  *         Number of cells in contact with the *i*-th point is
4314  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4315  *  \throw If the coordinates array is not set.
4316  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4317  *
4318  *  \if ENABLE_EXAMPLES
4319  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4320  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4321  *  \endif
4322  */
4323 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4324                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4325 {
4326   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4327   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4328 }
4329
4330 /*!
4331  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4332  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4333  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4334  * 
4335  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4336  */
4337 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4338 {
4339   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4340   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4341 }
4342
4343 /*!
4344  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4345  * least two its edges intersect each other anywhere except their extremities. An
4346  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4347  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4348  *         cleared before filling in.
4349  *  \param [in] eps - precision.
4350  *  \throw If \a this->getMeshDimension() != 2.
4351  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4352  */
4353 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4354 {
4355   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4356   if(getMeshDimension()!=2)
4357     throw INTERP_KERNEL::Exception(msg);
4358   int spaceDim=getSpaceDimension();
4359   if(spaceDim!=2 && spaceDim!=3)
4360     throw INTERP_KERNEL::Exception(msg);
4361   const mcIdType *conn=_nodal_connec->getConstPointer();
4362   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4363   mcIdType nbOfCells=getNumberOfCells();
4364   std::vector<double> cell2DinS2;
4365   for(mcIdType i=0;i<nbOfCells;i++)
4366     {
4367       mcIdType offset=connI[i];
4368       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4369       if(nbOfNodesForCell<=3)
4370         continue;
4371       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4372       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4373       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4374         cells.push_back(i);
4375       cell2DinS2.clear();
4376     }
4377 }
4378
4379 /*!
4380  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4381  *
4382  * 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.
4383  * 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.
4384  *
4385  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4386  * This convex envelop is computed using Jarvis march algorithm.
4387  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4388  * 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)
4389  * 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.
4390  *
4391  * \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.
4392  * \sa MEDCouplingUMesh::colinearize2D
4393  */
4394 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4395 {
4396   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4397     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4398   checkFullyDefined();
4399   const double *coords=getCoords()->getConstPointer();
4400   mcIdType nbOfCells=getNumberOfCells();
4401   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4402   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4403   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4404   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4405   *workIndexOut=0;
4406   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4407   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4408   std::set<INTERP_KERNEL::NormalizedCellType> types;
4409   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4410   isChanged->alloc(0,1);
4411   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4412     {
4413       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4414       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4415         isChanged->pushBackSilent(i);
4416       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4417       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4418     }
4419   if(isChanged->empty())
4420     return 0;
4421   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4422   _types=types;
4423   return isChanged.retn();
4424 }
4425
4426 /*!
4427  * This method is \b NOT const because it can modify \a this.
4428  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4429  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4430  * \param policy specifies the type of extrusion chosen:
4431  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4432  *   will be repeated to build each level
4433  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4434  *   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
4435  *   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
4436  *   arc.
4437  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4438  */
4439 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4440 {
4441   checkFullyDefined();
4442   mesh1D->checkFullyDefined();
4443   if(!mesh1D->isContiguous1D())
4444     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4445   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4446     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4447   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4448     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4449   if(mesh1D->getMeshDimension()!=1)
4450     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4451   bool isQuad=false;
4452   if(isPresenceOfQuadratic())
4453     {
4454       if(mesh1D->isFullyQuadratic())
4455         isQuad=true;
4456       else
4457         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4458     }
4459   mcIdType oldNbOfNodes(getNumberOfNodes());
4460   MCAuto<DataArrayDouble> newCoords;
4461   switch(policy)
4462   {
4463     case 0:
4464       {
4465         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4466         break;
4467       }
4468     case 1:
4469       {
4470         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4471         break;
4472       }
4473     default:
4474       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4475   }
4476   setCoords(newCoords);
4477   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4478   updateTime();
4479   return ret.retn();
4480 }
4481
4482
4483 /*!
4484  * Checks if \a this mesh is constituted by only quadratic cells.
4485  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4486  *  \throw If the coordinates array is not set.
4487  *  \throw If the nodal connectivity of cells is not defined.
4488  */
4489 bool MEDCouplingUMesh::isFullyQuadratic() const
4490 {
4491   checkFullyDefined();
4492   bool ret=true;
4493   mcIdType nbOfCells=getNumberOfCells();
4494   for(mcIdType i=0;i<nbOfCells && ret;i++)
4495     {
4496       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4497       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4498       ret=cm.isQuadratic();
4499     }
4500   return ret;
4501 }
4502
4503 /*!
4504  * Checks if \a this mesh includes any quadratic cell.
4505  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4506  *  \throw If the coordinates array is not set.
4507  *  \throw If the nodal connectivity of cells is not defined.
4508  */
4509 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4510 {
4511   checkFullyDefined();
4512   bool ret=false;
4513   mcIdType nbOfCells=getNumberOfCells();
4514   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4515     {
4516       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4517       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4518       ret=cm.isQuadratic();
4519     }
4520   return ret;
4521 }
4522
4523 /*!
4524  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4525  * this mesh, it remains unchanged.
4526  *  \throw If the coordinates array is not set.
4527  *  \throw If the nodal connectivity of cells is not defined.
4528  */
4529 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4530 {
4531   checkFullyDefined();
4532   mcIdType nbOfCells=getNumberOfCells();
4533   mcIdType delta=0;
4534   const mcIdType *iciptr=_nodal_connec_index->begin();
4535   for(mcIdType i=0;i<nbOfCells;i++)
4536     {
4537       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4538       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4539       if(cm.isQuadratic())
4540         {
4541           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4542           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4543           if(!cml.isDynamic())
4544             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4545           else
4546             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4547         }
4548     }
4549   if(delta==0)
4550     return ;
4551   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4552   const mcIdType *icptr(_nodal_connec->begin());
4553   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4554   newConnI->alloc(nbOfCells+1,1);
4555   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4556   *ociptr=0;
4557   _types.clear();
4558   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4559     {
4560       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4561       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4562       if(!cm.isQuadratic())
4563         {
4564           _types.insert(type);
4565           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4566           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4567         }
4568       else
4569         {
4570           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4571           _types.insert(typel);
4572           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4573           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4574           if(cml.isDynamic())
4575             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4576           *ocptr++=ToIdType(typel);
4577           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4578           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4579         }
4580     }
4581   setConnectivity(newConn,newConnI,false);
4582 }
4583
4584 /*!
4585  * This method converts all linear cell in \a this to quadratic one.
4586  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4587  * 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)
4588  * 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.
4589  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4590  * end of the existing coordinates.
4591  *
4592  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4593  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4594  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4595  *
4596  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4597  *
4598  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4599  */
4600 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4601 {
4602   DataArrayIdType *conn=0,*connI=0;
4603   DataArrayDouble *coords=0;
4604   std::set<INTERP_KERNEL::NormalizedCellType> types;
4605   checkFullyDefined();
4606   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4607   MCAuto<DataArrayDouble> coordsSafe;
4608   int meshDim=getMeshDimension();
4609   switch(conversionType)
4610   {
4611     case 0:
4612       switch(meshDim)
4613       {
4614         case 1:
4615           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4616           connSafe=conn; connISafe=connI; coordsSafe=coords;
4617           break;
4618         case 2:
4619           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4620           connSafe=conn; connISafe=connI; coordsSafe=coords;
4621           break;
4622         case 3:
4623           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4624           connSafe=conn; connISafe=connI; coordsSafe=coords;
4625           break;
4626         default:
4627           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4628       }
4629       break;
4630         case 1:
4631           {
4632             switch(meshDim)
4633             {
4634               case 1:
4635                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4636                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4637                 break;
4638               case 2:
4639                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4640                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4641                 break;
4642               case 3:
4643                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4644                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4645                 break;
4646               default:
4647                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4648             }
4649             break;
4650           }
4651         default:
4652           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4653   }
4654   setConnectivity(connSafe,connISafe,false);
4655   _types=types;
4656   setCoords(coordsSafe);
4657   return ret.retn();
4658 }
4659
4660 /*!
4661  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4662  * so that the number of cells remains the same. Quadratic faces are converted to
4663  * polygons. This method works only for 2D meshes in
4664  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4665  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4666  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4667  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4668  *         a polylinized edge constituting the input polygon.
4669  *  \throw If the coordinates array is not set.
4670  *  \throw If the nodal connectivity of cells is not defined.
4671  *  \throw If \a this->getMeshDimension() != 2.
4672  *  \throw If \a this->getSpaceDimension() != 2.
4673  */
4674 void MEDCouplingUMesh::tessellate2D(double eps)
4675 {
4676   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4677   if(spaceDim!=2)
4678     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4679   switch(meshDim)
4680     {
4681     case 1:
4682       return tessellate2DCurveInternal(eps);
4683     case 2:
4684       return tessellate2DInternal(eps);
4685     default:
4686       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4687     }
4688 }
4689
4690 #if 0
4691 /*!
4692  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4693  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4694  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4695  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4696  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4697  * This method can be seen as the opposite method of colinearize2D.
4698  * 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
4699  * to avoid to modify the numbering of existing nodes.
4700  *
4701  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4702  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4703  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4704  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4705  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4706  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4707  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4708  *
4709  * \sa buildDescendingConnectivity2
4710  */
4711 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4712                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4713 {
4714   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4715     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4716   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4717   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4718     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4719   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4720     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4721   //DataArrayIdType *out0(0),*outi0(0);
4722   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4723   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4724   //out0s=out0s->buildUnique(); out0s->sort(true);
4725 }
4726 #endif
4727
4728
4729 /*!
4730  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4731  * In addition, returns an array mapping new cells to old ones. <br>
4732  * This method typically increases the number of cells in \a this mesh
4733  * but the number of nodes remains \b unchanged.
4734  * That's why the 3D splitting policies
4735  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4736  *  \param [in] policy - specifies a pattern used for splitting.
4737  * The semantic of \a policy is:
4738  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4739  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4740  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4741  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4742  *
4743  *
4744  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4745  *          an id of old cell producing it. The caller is to delete this array using
4746  *         decrRef() as it is no more needed.
4747  *
4748  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4749  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4750  *          and \a this->getMeshDimension() != 3.
4751  *  \throw If \a policy is not one of the four discussed above.
4752  *  \throw If the nodal connectivity of cells is not defined.
4753  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4754  */
4755 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4756 {
4757   switch(policy)
4758   {
4759     case 0:
4760       return simplexizePol0();
4761     case 1:
4762       return simplexizePol1();
4763     case INTERP_KERNEL::PLANAR_FACE_5:
4764         return simplexizePlanarFace5();
4765     case INTERP_KERNEL::PLANAR_FACE_6:
4766         return simplexizePlanarFace6();
4767     default:
4768       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)");
4769   }
4770 }
4771
4772 /*!
4773  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4774  * - 1D: INTERP_KERNEL::NORM_SEG2
4775  * - 2D: INTERP_KERNEL::NORM_TRI3
4776  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4777  *
4778  * This method is useful for users that need to use P1 field services as
4779  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4780  * All these methods need mesh support containing only simplex cells.
4781  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4782  *  \throw If the coordinates array is not set.
4783  *  \throw If the nodal connectivity of cells is not defined.
4784  *  \throw If \a this->getMeshDimension() < 1.
4785  */
4786 bool MEDCouplingUMesh::areOnlySimplexCells() const
4787 {
4788   checkFullyDefined();
4789   int mdim=getMeshDimension();
4790   if(mdim<1 || mdim>3)
4791     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4792   mcIdType nbCells=getNumberOfCells();
4793   const mcIdType *conn=_nodal_connec->begin();
4794   const mcIdType *connI=_nodal_connec_index->begin();
4795   for(mcIdType i=0;i<nbCells;i++)
4796     {
4797       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4798       if(!cm.isSimplex())
4799         return false;
4800     }
4801   return true;
4802 }
4803
4804
4805
4806 /*!
4807  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4808  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4809  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4810  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4811  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4812  * so it can be useful to call mergeNodes() before calling this method.
4813  *  \throw If \a this->getMeshDimension() <= 1.
4814  *  \throw If the coordinates array is not set.
4815  *  \throw If the nodal connectivity of cells is not defined.
4816  */
4817 void MEDCouplingUMesh::convertDegeneratedCells()
4818 {
4819   checkFullyDefined();
4820   if(getMeshDimension()<=1)
4821     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4822   mcIdType nbOfCells=getNumberOfCells();
4823   if(nbOfCells<1)
4824     return ;
4825   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4826   mcIdType *conn=_nodal_connec->getPointer();
4827   mcIdType *index=_nodal_connec_index->getPointer();
4828   mcIdType posOfCurCell=0;
4829   mcIdType newPos=0;
4830   mcIdType lgthOfCurCell;
4831   for(mcIdType i=0;i<nbOfCells;i++)
4832     {
4833       lgthOfCurCell=index[i+1]-posOfCurCell;
4834       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4835       mcIdType newLgth;
4836       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4837                                                                                                      conn+newPos+1,newLgth);
4838       conn[newPos]=newType;
4839       newPos+=newLgth+1;
4840       posOfCurCell=index[i+1];
4841       index[i+1]=newPos;
4842     }
4843   if(newPos!=initMeshLgth)
4844     _nodal_connec->reAlloc(newPos);
4845   computeTypes();
4846 }
4847
4848 /*!
4849  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4850  * A cell is flat in the following cases:
4851  *   - for a linear cell, all points in the connectivity are equal
4852  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4853  *   identical quadratic points
4854  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4855  *      this array using decrRef() as it is no more needed.
4856  */
4857 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4858 {
4859   checkFullyDefined();
4860   if(getMeshDimension()<=1)
4861     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4862   mcIdType nbOfCells=getNumberOfCells();
4863   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4864   if(nbOfCells<1)
4865     return ret.retn();
4866   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4867   mcIdType *conn=_nodal_connec->getPointer();
4868   mcIdType *index=_nodal_connec_index->getPointer();
4869   mcIdType posOfCurCell=0;
4870   mcIdType newPos=0;
4871   mcIdType lgthOfCurCell, nbDelCells(0);
4872   for(mcIdType i=0;i<nbOfCells;i++)
4873     {
4874       lgthOfCurCell=index[i+1]-posOfCurCell;
4875       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4876       mcIdType newLgth;
4877       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4878                                                                                                      conn+newPos+1,newLgth);
4879       // Shall we delete the cell if it is completely degenerated:
4880       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4881       if (delCell)
4882         {
4883           nbDelCells++;
4884           ret->pushBackSilent(i);
4885         }
4886       else   //if the cell is to be deleted, simply stay at the same place
4887         {
4888           conn[newPos]=newType;
4889           newPos+=newLgth+1;
4890         }
4891       posOfCurCell=index[i+1];
4892       index[i+1-nbDelCells]=newPos;
4893     }
4894   if(newPos!=initMeshLgth)
4895     _nodal_connec->reAlloc(newPos);
4896   const mcIdType nCellDel=ret->getNumberOfTuples();
4897   if (nCellDel)
4898     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4899   computeTypes();
4900   return ret.retn();
4901 }
4902
4903 /*!
4904  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4905  * Only connectivity is considered here.
4906  */
4907 bool MEDCouplingUMesh::removeDegenerated1DCells()
4908 {
4909   checkConnectivityFullyDefined();
4910   if(getMeshDimension()!=1)
4911     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4912   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4913   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4914   {
4915     for(std::size_t i=0;i<nbCells;i++)
4916       {
4917         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4918         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4919           {
4920             if(conn[conni[i]+1]!=conn[conni[i]+2])
4921               {
4922                 newSize++;
4923                 newSize2+=conni[i+1]-conni[i];
4924               }
4925           }
4926         else
4927           {
4928             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4929             throw INTERP_KERNEL::Exception(oss.str());
4930           }
4931       }
4932   }
4933   if(newSize==nbCells)//no cells has been removed -> do nothing
4934     return false;
4935   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4936   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4937   for(std::size_t i=0;i<nbCells;i++)
4938     {
4939       if(conn[conni[i]+1]!=conn[conni[i]+2])
4940         {
4941           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4942           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4943           newConnIPtr++;
4944         }
4945     }
4946   setConnectivity(newConn,newConnI,true);
4947   return true;
4948 }
4949
4950 /*!
4951  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4952  * A cell is considered to be oriented correctly if an angle between its
4953  * normal vector and a given vector is less than \c PI / \c 2.
4954  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4955  *         cells.
4956  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4957  *         checked.
4958  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4959  *         is not cleared before filling in.
4960  *  \throw If \a this->getMeshDimension() != 2.
4961  *  \throw If \a this->getSpaceDimension() != 3.
4962  *
4963  *  \if ENABLE_EXAMPLES
4964  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4965  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4966  *  \endif
4967  */
4968 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4969 {
4970   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4971     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4972   mcIdType nbOfCells=getNumberOfCells();
4973   const mcIdType *conn=_nodal_connec->begin();
4974   const mcIdType *connI=_nodal_connec_index->begin();
4975   const double *coordsPtr=_coords->begin();
4976   for(mcIdType i=0;i<nbOfCells;i++)
4977     {
4978       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4979       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4980         {
4981           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4982           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4983             cells.push_back(i);
4984         }
4985     }
4986 }
4987
4988 /*!
4989  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4990  * considered to be oriented correctly if an angle between its normal vector and a
4991  * given vector is less than \c PI / \c 2.
4992  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4993  *         cells.
4994  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4995  *         checked.
4996  *  \throw If \a this->getMeshDimension() != 2.
4997  *  \throw If \a this->getSpaceDimension() != 3.
4998  *
4999  *  \if ENABLE_EXAMPLES
5000  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
5001  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
5002  *  \endif
5003  *
5004  *  \sa changeOrientationOfCells
5005  */
5006 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
5007 {
5008   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5009     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
5010   mcIdType nbOfCells=getNumberOfCells();
5011   mcIdType *conn(_nodal_connec->getPointer());
5012   const mcIdType *connI(_nodal_connec_index->begin());
5013   const double *coordsPtr(_coords->begin());
5014   bool isModified(false);
5015   for(mcIdType i=0;i<nbOfCells;i++)
5016     {
5017       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5018       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
5019         {
5020           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5021           bool isQuadratic(cm.isQuadratic());
5022           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5023             {
5024               isModified=true;
5025               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5026             }
5027         }
5028     }
5029   if(isModified)
5030     _nodal_connec->declareAsNew();
5031   updateTime();
5032 }
5033
5034 /*!
5035  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
5036  *
5037  * \sa orientCorrectly2DCells
5038  */
5039 void MEDCouplingUMesh::changeOrientationOfCells()
5040 {
5041   int mdim(getMeshDimension());
5042   if(mdim!=2 && mdim!=1)
5043     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
5044   mcIdType nbOfCells=getNumberOfCells();
5045   mcIdType *conn(_nodal_connec->getPointer());
5046   const mcIdType *connI(_nodal_connec_index->begin());
5047   if(mdim==2)
5048     {//2D
5049       for(mcIdType i=0;i<nbOfCells;i++)
5050         {
5051           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5052           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5053           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5054         }
5055     }
5056   else
5057     {//1D
5058       for(mcIdType i=0;i<nbOfCells;i++)
5059         {
5060           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5061           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
5062           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
5063         }
5064     }
5065 }
5066
5067 /*!
5068  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
5069  * oriented facets. The normal vector of the facet should point out of the cell.
5070  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
5071  *         is not cleared before filling in.
5072  *  \throw If \a this->getMeshDimension() != 3.
5073  *  \throw If \a this->getSpaceDimension() != 3.
5074  *  \throw If the coordinates array is not set.
5075  *  \throw If the nodal connectivity of cells is not defined.
5076  *
5077  *  \if ENABLE_EXAMPLES
5078  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5079  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5080  *  \endif
5081  */
5082 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
5083 {
5084   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5085     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
5086   mcIdType nbOfCells=getNumberOfCells();
5087   const mcIdType *conn=_nodal_connec->begin();
5088   const mcIdType *connI=_nodal_connec_index->begin();
5089   const double *coordsPtr=_coords->begin();
5090   for(mcIdType i=0;i<nbOfCells;i++)
5091     {
5092       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5093       if(type==INTERP_KERNEL::NORM_POLYHED)
5094         {
5095           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5096             cells.push_back(i);
5097         }
5098     }
5099 }
5100
5101 /*!
5102  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
5103  * out of the cell.
5104  *  \throw If \a this->getMeshDimension() != 3.
5105  *  \throw If \a this->getSpaceDimension() != 3.
5106  *  \throw If the coordinates array is not set.
5107  *  \throw If the nodal connectivity of cells is not defined.
5108  *  \throw If the reparation fails.
5109  *
5110  *  \if ENABLE_EXAMPLES
5111  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
5112  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
5113  *  \endif
5114  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5115  */
5116 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
5117 {
5118   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5119     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
5120   mcIdType nbOfCells=getNumberOfCells();
5121   mcIdType *conn=_nodal_connec->getPointer();
5122   const mcIdType *connI=_nodal_connec_index->begin();
5123   const double *coordsPtr=_coords->begin();
5124   for(mcIdType i=0;i<nbOfCells;i++)
5125     {
5126       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5127       if(type==INTERP_KERNEL::NORM_POLYHED)
5128         {
5129           try
5130           {
5131               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5132                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5133           }
5134           catch(INTERP_KERNEL::Exception& e)
5135           {
5136               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
5137               throw INTERP_KERNEL::Exception(oss.str());
5138           }
5139         }
5140     }
5141   updateTime();
5142 }
5143
5144 /*!
5145  * This method invert orientation of all cells in \a this.
5146  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
5147  * This method only operates on the connectivity so coordinates are not touched at all.
5148  */
5149 void MEDCouplingUMesh::invertOrientationOfAllCells()
5150 {
5151   checkConnectivityFullyDefined();
5152   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
5153   mcIdType *conn(_nodal_connec->getPointer());
5154   const mcIdType *conni(_nodal_connec_index->begin());
5155   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
5156     {
5157       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
5158       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
5159       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
5160         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
5161     }
5162   updateTime();
5163 }
5164
5165 /*!
5166  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5167  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5168  * according to which the first facet of the cell should be oriented to have the normal vector
5169  * pointing out of cell.
5170  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5171  *         cells. The caller is to delete this array using decrRef() as it is no more
5172  *         needed.
5173  *  \throw If \a this->getMeshDimension() != 3.
5174  *  \throw If \a this->getSpaceDimension() != 3.
5175  *  \throw If the coordinates array is not set.
5176  *  \throw If the nodal connectivity of cells is not defined.
5177  *
5178  *  \if ENABLE_EXAMPLES
5179  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5180  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5181  *  \endif
5182  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5183  */
5184 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5185 {
5186   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5187   if(getMeshDimension()!=3)
5188     throw INTERP_KERNEL::Exception(msg);
5189   int spaceDim=getSpaceDimension();
5190   if(spaceDim!=3)
5191     throw INTERP_KERNEL::Exception(msg);
5192   //
5193   mcIdType nbOfCells=getNumberOfCells();
5194   mcIdType *conn=_nodal_connec->getPointer();
5195   const mcIdType *connI=_nodal_connec_index->begin();
5196   const double *coo=getCoords()->begin();
5197   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5198   for(mcIdType i=0;i<nbOfCells;i++)
5199     {
5200       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5201       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5202         {
5203           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5204             {
5205               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5206               cells->pushBackSilent(i);
5207             }
5208         }
5209     }
5210   return cells.retn();
5211 }
5212
5213 /*!
5214  * This method is a faster method to correct orientation of all 3D cells in \a this.
5215  * 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.
5216  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5217  *
5218  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5219  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5220  */
5221 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5222 {
5223   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5224     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5225   mcIdType nbOfCells=getNumberOfCells();
5226   mcIdType *conn=_nodal_connec->getPointer();
5227   const mcIdType *connI=_nodal_connec_index->begin();
5228   const double *coordsPtr=_coords->begin();
5229   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5230   for(mcIdType i=0;i<nbOfCells;i++)
5231     {
5232       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5233       switch(type)
5234       {
5235         case INTERP_KERNEL::NORM_TETRA4:
5236           {
5237             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5238               {
5239                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5240                 ret->pushBackSilent(i);
5241               }
5242             break;
5243           }
5244         case INTERP_KERNEL::NORM_PYRA5:
5245           {
5246             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5247               {
5248                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5249                 ret->pushBackSilent(i);
5250               }
5251             break;
5252           }
5253         case INTERP_KERNEL::NORM_PENTA6:
5254         case INTERP_KERNEL::NORM_HEXA8:
5255         case INTERP_KERNEL::NORM_HEXGP12:
5256           {
5257             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5258               {
5259                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5260                 ret->pushBackSilent(i);
5261               }
5262             break;
5263           }
5264         case INTERP_KERNEL::NORM_POLYHED:
5265           {
5266             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5267               {
5268                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5269                 ret->pushBackSilent(i);
5270               }
5271             break;
5272           }
5273         default:
5274           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 !");
5275       }
5276     }
5277   updateTime();
5278   return ret.retn();
5279 }
5280
5281 /*!
5282  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5283  * If it is not the case an exception will be thrown.
5284  * This method is fast because the first cell of \a this is used to compute the plane.
5285  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5286  * \param pos output of size at least 3 used to store a point owned of searched plane.
5287  */
5288 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5289 {
5290   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5291     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5292   const mcIdType *conn=_nodal_connec->begin();
5293   const mcIdType *connI=_nodal_connec_index->begin();
5294   const double *coordsPtr=_coords->begin();
5295   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5296   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5297 }
5298
5299 /*!
5300  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5301  * cells. Currently cells of the following types are treated:
5302  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5303  * For a cell of other type an exception is thrown.
5304  * Space dimension of a 2D mesh can be either 2 or 3.
5305  * The Edge Ratio of a cell \f$t\f$ is:
5306  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5307  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5308  *  the smallest edge lengths of \f$t\f$.
5309  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5310  *          cells and one time, lying on \a this mesh. The caller is to delete this
5311  *          field using decrRef() as it is no more needed.
5312  *  \throw If the coordinates array is not set.
5313  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5314  *  \throw If the connectivity data array has more than one component.
5315  *  \throw If the connectivity data array has a named component.
5316  *  \throw If the connectivity index data array has more than one component.
5317  *  \throw If the connectivity index data array has a named component.
5318  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5319  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5320  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5321  */
5322 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5323 {
5324   checkConsistencyLight();
5325   int spaceDim=getSpaceDimension();
5326   int meshDim=getMeshDimension();
5327   if(spaceDim!=2 && spaceDim!=3)
5328     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5329   if(meshDim!=2 && meshDim!=3)
5330     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5331   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5332   ret->setMesh(this);
5333   mcIdType nbOfCells=getNumberOfCells();
5334   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5335   arr->alloc(nbOfCells,1);
5336   double *pt=arr->getPointer();
5337   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5338   const mcIdType *conn=_nodal_connec->begin();
5339   const mcIdType *connI=_nodal_connec_index->begin();
5340   const double *coo=_coords->begin();
5341   double tmp[12];
5342   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5343     {
5344       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5345       switch(t)
5346       {
5347         case INTERP_KERNEL::NORM_TRI3:
5348           {
5349             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5350             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5351             break;
5352           }
5353         case INTERP_KERNEL::NORM_QUAD4:
5354           {
5355             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5356             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5357             break;
5358           }
5359         case INTERP_KERNEL::NORM_TETRA4:
5360           {
5361             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5362             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5363             break;
5364           }
5365         default:
5366           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5367       }
5368       conn+=connI[i+1]-connI[i];
5369     }
5370   ret->setName("EdgeRatio");
5371   ret->synchronizeTimeWithSupport();
5372   return ret.retn();
5373 }
5374
5375 /*!
5376  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5377  * cells. Currently cells of the following types are treated:
5378  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5379  * For a cell of other type an exception is thrown.
5380  * Space dimension of a 2D mesh can be either 2 or 3.
5381  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5382  *          cells and one time, lying on \a this mesh. The caller is to delete this
5383  *          field using decrRef() as it is no more needed.
5384  *  \throw If the coordinates array is not set.
5385  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5386  *  \throw If the connectivity data array has more than one component.
5387  *  \throw If the connectivity data array has a named component.
5388  *  \throw If the connectivity index data array has more than one component.
5389  *  \throw If the connectivity index data array has a named component.
5390  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5391  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5392  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5393  */
5394 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5395 {
5396   checkConsistencyLight();
5397   int spaceDim=getSpaceDimension();
5398   int meshDim=getMeshDimension();
5399   if(spaceDim!=2 && spaceDim!=3)
5400     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5401   if(meshDim!=2 && meshDim!=3)
5402     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5403   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5404   ret->setMesh(this);
5405   mcIdType nbOfCells=getNumberOfCells();
5406   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5407   arr->alloc(nbOfCells,1);
5408   double *pt=arr->getPointer();
5409   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5410   const mcIdType *conn=_nodal_connec->begin();
5411   const mcIdType *connI=_nodal_connec_index->begin();
5412   const double *coo=_coords->begin();
5413   double tmp[12];
5414   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5415     {
5416       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5417       switch(t)
5418       {
5419         case INTERP_KERNEL::NORM_TRI3:
5420           {
5421             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5422             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5423             break;
5424           }
5425         case INTERP_KERNEL::NORM_QUAD4:
5426           {
5427             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5428             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5429             break;
5430           }
5431         case INTERP_KERNEL::NORM_TETRA4:
5432           {
5433             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5434             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5435             break;
5436           }
5437         default:
5438           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5439       }
5440       conn+=connI[i+1]-connI[i];
5441     }
5442   ret->setName("AspectRatio");
5443   ret->synchronizeTimeWithSupport();
5444   return ret.retn();
5445 }
5446
5447 /*!
5448  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5449  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5450  * in 3D space. Currently only cells of the following types are
5451  * treated: INTERP_KERNEL::NORM_QUAD4.
5452  * For a cell of other type an exception is thrown.
5453  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5454  * Defining
5455  * \f$t=\vec{da}\times\vec{ab}\f$,
5456  * \f$u=\vec{ab}\times\vec{bc}\f$
5457  * \f$v=\vec{bc}\times\vec{cd}\f$
5458  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5459  *  \f[
5460  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5461  *  \f]
5462  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5463  *          cells and one time, lying on \a this mesh. The caller is to delete this
5464  *          field using decrRef() as it is no more needed.
5465  *  \throw If the coordinates array is not set.
5466  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5467  *  \throw If the connectivity data array has more than one component.
5468  *  \throw If the connectivity data array has a named component.
5469  *  \throw If the connectivity index data array has more than one component.
5470  *  \throw If the connectivity index data array has a named component.
5471  *  \throw If \a this->getMeshDimension() != 2.
5472  *  \throw If \a this->getSpaceDimension() != 3.
5473  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5474  */
5475 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5476 {
5477   checkConsistencyLight();
5478   int spaceDim=getSpaceDimension();
5479   int meshDim=getMeshDimension();
5480   if(spaceDim!=3)
5481     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5482   if(meshDim!=2)
5483     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5484   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5485   ret->setMesh(this);
5486   mcIdType nbOfCells=getNumberOfCells();
5487   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5488   arr->alloc(nbOfCells,1);
5489   double *pt=arr->getPointer();
5490   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5491   const mcIdType *conn=_nodal_connec->begin();
5492   const mcIdType *connI=_nodal_connec_index->begin();
5493   const double *coo=_coords->begin();
5494   double tmp[12];
5495   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5496     {
5497       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5498       switch(t)
5499       {
5500         case INTERP_KERNEL::NORM_QUAD4:
5501           {
5502             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5503             *pt=INTERP_KERNEL::quadWarp(tmp);
5504             break;
5505           }
5506         default:
5507           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5508       }
5509       conn+=connI[i+1]-connI[i];
5510     }
5511   ret->setName("Warp");
5512   ret->synchronizeTimeWithSupport();
5513   return ret.retn();
5514 }
5515
5516
5517 /*!
5518  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5519  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5520  * treated: INTERP_KERNEL::NORM_QUAD4.
5521  * The skew is computed as follow for a quad with points (a,b,c,d): let
5522  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5523  * then the skew is computed as:
5524  *  \f[
5525  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5526  *  \f]
5527  *
5528  * For a cell of other type an exception is thrown.
5529  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5530  *          cells and one time, lying on \a this mesh. The caller is to delete this
5531  *          field using decrRef() as it is no more needed.
5532  *  \throw If the coordinates array is not set.
5533  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5534  *  \throw If the connectivity data array has more than one component.
5535  *  \throw If the connectivity data array has a named component.
5536  *  \throw If the connectivity index data array has more than one component.
5537  *  \throw If the connectivity index data array has a named component.
5538  *  \throw If \a this->getMeshDimension() != 2.
5539  *  \throw If \a this->getSpaceDimension() != 3.
5540  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5541  */
5542 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5543 {
5544   checkConsistencyLight();
5545   int spaceDim=getSpaceDimension();
5546   int meshDim=getMeshDimension();
5547   if(spaceDim!=3)
5548     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5549   if(meshDim!=2)
5550     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5551   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5552   ret->setMesh(this);
5553   mcIdType nbOfCells=getNumberOfCells();
5554   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5555   arr->alloc(nbOfCells,1);
5556   double *pt=arr->getPointer();
5557   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5558   const mcIdType *conn=_nodal_connec->begin();
5559   const mcIdType *connI=_nodal_connec_index->begin();
5560   const double *coo=_coords->begin();
5561   double tmp[12];
5562   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5563     {
5564       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5565       switch(t)
5566       {
5567         case INTERP_KERNEL::NORM_QUAD4:
5568           {
5569             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5570             *pt=INTERP_KERNEL::quadSkew(tmp);
5571             break;
5572           }
5573         default:
5574           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5575       }
5576       conn+=connI[i+1]-connI[i];
5577     }
5578   ret->setName("Skew");
5579   ret->synchronizeTimeWithSupport();
5580   return ret.retn();
5581 }
5582
5583 /*!
5584  * 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.
5585  *
5586  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5587  *
5588  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5589  */
5590 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5591 {
5592   checkConsistencyLight();
5593   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5594   ret->setMesh(this);
5595   std::set<INTERP_KERNEL::NormalizedCellType> types;
5596   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5597   int spaceDim(getSpaceDimension());
5598   mcIdType nbCells(getNumberOfCells());
5599   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5600   arr->alloc(nbCells,1);
5601   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5602     {
5603       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5604       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5605       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5606     }
5607   ret->setArray(arr);
5608   ret->setName("Diameter");
5609   return ret.retn();
5610 }
5611
5612 /*!
5613  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5614  *
5615  * \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)
5616  *                         For all other cases this input parameter is ignored.
5617  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5618  *
5619  * \throw If \a this is not fully set (coordinates and connectivity).
5620  * \throw If a cell in \a this has no valid nodeId.
5621  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5622  */
5623 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5624 {
5625   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5626   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.
5627     return getBoundingBoxForBBTreeFast();
5628   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5629     {
5630       bool presenceOfQuadratic(false);
5631       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5632         {
5633           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5634           if(cm.isQuadratic())
5635             presenceOfQuadratic=true;
5636         }
5637       if(!presenceOfQuadratic)
5638         return getBoundingBoxForBBTreeFast();
5639       if(mDim==2 && sDim==2)
5640         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5641       else
5642         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5643     }
5644   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) !");
5645 }
5646
5647 /*!
5648  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5649  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5650  *
5651  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5652  *
5653  * \throw If \a this is not fully set (coordinates and connectivity).
5654  * \throw If a cell in \a this has no valid nodeId.
5655  */
5656 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5657 {
5658   checkFullyDefined();
5659   int spaceDim(getSpaceDimension());
5660   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5661   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5662   double *bbox(ret->getPointer());
5663   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5664     {
5665       bbox[2*i]=std::numeric_limits<double>::max();
5666       bbox[2*i+1]=-std::numeric_limits<double>::max();
5667     }
5668   const double *coordsPtr(_coords->begin());
5669   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5670   for(mcIdType i=0;i<nbOfCells;i++)
5671     {
5672       mcIdType offset=connI[i]+1;
5673       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5674       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5675         {
5676           mcIdType nodeId=conn[offset+j];
5677           if(nodeId>=0 && nodeId<nbOfNodes)
5678             {
5679               for(int k=0;k<spaceDim;k++)
5680                 {
5681                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5682                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5683                 }
5684               kk++;
5685             }
5686         }
5687       if(kk==0)
5688         {
5689           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5690           throw INTERP_KERNEL::Exception(oss.str());
5691         }
5692     }
5693   return ret.retn();
5694 }
5695
5696 /*!
5697  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5698  * useful for 2D meshes having quadratic cells
5699  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5700  * the two extremities of the arc of circle).
5701  *
5702  * \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)
5703  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5704  * \throw If \a this is not fully defined.
5705  * \throw If \a this is not a mesh with meshDimension equal to 2.
5706  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5707  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5708  */
5709 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5710 {
5711   checkFullyDefined();
5712   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5713
5714   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5715   mcIdType nbOfCells=getNumberOfCells();
5716   if(spaceDim!=2 || mDim!=2)
5717     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!");
5718   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5719   double *bbox(ret->getPointer());
5720   const double *coords(_coords->begin());
5721   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5722   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5723     {
5724       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5725       mcIdType sz(connI[1]-connI[0]-1);
5726       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5727       INTERP_KERNEL::QuadraticPolygon *pol(0);
5728       for(mcIdType j=0;j<sz;j++)
5729         {
5730           mcIdType nodeId(conn[*connI+1+j]);
5731           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5732         }
5733       if(!cm.isQuadratic())
5734         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5735       else
5736         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5737       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5738       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5739     }
5740   return ret.retn();
5741 }
5742
5743 /*!
5744  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5745  * useful for 2D meshes having quadratic cells
5746  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5747  * the two extremities of the arc of circle).
5748  *
5749  * \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)
5750  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5751  * \throw If \a this is not fully defined.
5752  * \throw If \a this is not a mesh with meshDimension equal to 1.
5753  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5754  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5755  */
5756 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5757 {
5758   checkFullyDefined();
5759   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5760   mcIdType nbOfCells=getNumberOfCells();
5761   if(spaceDim!=2 || mDim!=1)
5762     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!");
5763   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5764   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5765   double *bbox(ret->getPointer());
5766   const double *coords(_coords->begin());
5767   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5768   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5769     {
5770       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5771       mcIdType sz(connI[1]-connI[0]-1);
5772       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5773       INTERP_KERNEL::Edge *edge(0);
5774       for(mcIdType j=0;j<sz;j++)
5775         {
5776           mcIdType nodeId(conn[*connI+1+j]);
5777           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5778         }
5779       if(!cm.isQuadratic())
5780         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5781       else
5782         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5783       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5784       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5785     }
5786   return ret.retn();
5787 }
5788
5789 /// @cond INTERNAL
5790
5791 namespace MEDCouplingImpl
5792 {
5793   class ConnReader
5794   {
5795   public:
5796     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5797     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5798   private:
5799     const mcIdType *_conn;
5800     mcIdType _val;
5801   };
5802
5803   class ConnReader2
5804   {
5805   public:
5806     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5807     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5808   private:
5809     const mcIdType *_conn;
5810     mcIdType _val;
5811   };
5812 }
5813
5814 /// @endcond
5815
5816 /*!
5817  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5818  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5819  * \a this is composed in cell types.
5820  * The returned array is of size 3*n where n is the number of different types present in \a this.
5821  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5822  * This parameter is kept only for compatibility with other method listed above.
5823  */
5824 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5825 {
5826   checkConnectivityFullyDefined();
5827   const mcIdType *conn=_nodal_connec->begin();
5828   const mcIdType *connI=_nodal_connec_index->begin();
5829   const mcIdType *work=connI;
5830   mcIdType nbOfCells=getNumberOfCells();
5831   std::size_t n=getAllGeoTypes().size();
5832   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5833   std::set<INTERP_KERNEL::NormalizedCellType> types;
5834   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5835     {
5836       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5837       if(types.find(typ)!=types.end())
5838         {
5839           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5840           oss << " is not contiguous !";
5841           throw INTERP_KERNEL::Exception(oss.str());
5842         }
5843       types.insert(typ);
5844       ret[3*i]=typ;
5845       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5846       ret[3*i+1]=ToIdType(std::distance(work,work2));
5847       work=work2;
5848     }
5849   return ret;
5850 }
5851
5852 /*!
5853  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5854  * only for types cell, type node is not managed.
5855  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5856  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5857  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5858  * If 2 or more same geometric type is in \a code and exception is thrown too.
5859  *
5860  * This method firstly checks
5861  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5862  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5863  * an exception is thrown too.
5864  *
5865  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5866  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5867  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5868  */
5869 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5870 {
5871   if(code.empty())
5872     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5873   std::size_t sz=code.size();
5874   std::size_t n=sz/3;
5875   if(sz%3!=0)
5876     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5877   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5878   mcIdType nb=0;
5879   bool isNoPflUsed=true;
5880   for(std::size_t i=0;i<n;i++)
5881     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5882       {
5883         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5884         nb+=code[3*i+1];
5885         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5886           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5887         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5888       }
5889   if(types.size()!=n)
5890     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5891   if(isNoPflUsed)
5892     {
5893       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5894         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5895       if(types.size()==_types.size())
5896         return 0;
5897     }
5898   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5899   ret->alloc(nb,1);
5900   mcIdType *retPtr=ret->getPointer();
5901   const mcIdType *connI=_nodal_connec_index->begin();
5902   const mcIdType *conn=_nodal_connec->begin();
5903   mcIdType nbOfCells=getNumberOfCells();
5904   const mcIdType *i=connI;
5905   int kk=0;
5906   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5907     {
5908       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5909       mcIdType offset=ToIdType(std::distance(connI,i));
5910       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5911       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5912       if(code[3*kk+2]==-1)
5913         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5914           *retPtr++=k+offset;
5915       else
5916         {
5917           mcIdType idInIdsPerType=code[3*kk+2];
5918           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5919             {
5920               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5921               if(zePfl)
5922                 {
5923                   zePfl->checkAllocated();
5924                   if(zePfl->getNumberOfComponents()==1)
5925                     {
5926                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5927                         {
5928                           if(*k>=0 && *k<nbOfCellsOfCurType)
5929                             *retPtr=(*k)+offset;
5930                           else
5931                             {
5932                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5933                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5934                               throw INTERP_KERNEL::Exception(oss.str());
5935                             }
5936                         }
5937                     }
5938                   else
5939                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5940                 }
5941               else
5942                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5943             }
5944           else
5945             {
5946               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5947               oss << " should be in [0," << idsPerType.size() << ") !";
5948               throw INTERP_KERNEL::Exception(oss.str());
5949             }
5950         }
5951       i=j;
5952     }
5953   return ret.retn();
5954 }
5955
5956 /*!
5957  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5958  * 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.
5959  * 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.
5960  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5961  *
5962  * \param [in] profile list of IDs constituing the profile
5963  * \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.
5964  * \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,
5965  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5966  * \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.
5967  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5968  * \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
5969  */
5970 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5971 {
5972   if(!profile)
5973     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5974   if(profile->getNumberOfComponents()!=1)
5975     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5976   checkConnectivityFullyDefined();
5977   const mcIdType *conn=_nodal_connec->begin();
5978   const mcIdType *connI=_nodal_connec_index->begin();
5979   mcIdType nbOfCells=getNumberOfCells();
5980   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5981   std::vector<mcIdType> typeRangeVals(1);
5982   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5983     {
5984       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5985       if(std::find(types.begin(),types.end(),curType)!=types.end())
5986         {
5987           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5988         }
5989       types.push_back(curType);
5990       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5991       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5992     }
5993   //
5994   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5995   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5996   MCAuto<DataArrayIdType> tmp0=castArr;
5997   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5998   MCAuto<DataArrayIdType> tmp2=castsPresent;
5999   //
6000   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
6001   code.resize(3*nbOfCastsFinal);
6002   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
6003   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
6004   for(mcIdType i=0;i<nbOfCastsFinal;i++)
6005     {
6006       mcIdType castId=castsPresent->getIJ(i,0);
6007       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
6008       idsInPflPerType2.push_back(tmp3);
6009       code[3*i]=ToIdType(types[castId]);
6010       code[3*i+1]=tmp3->getNumberOfTuples();
6011       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
6012       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
6013         {
6014           tmp4->copyStringInfoFrom(*profile);
6015           idsPerType2.push_back(tmp4);
6016           code[3*i+2]=ToIdType(idsPerType2.size())-1;
6017         }
6018       else
6019         {
6020           code[3*i+2]=-1;
6021         }
6022     }
6023   std::size_t sz2=idsInPflPerType2.size();
6024   idsInPflPerType.resize(sz2);
6025   for(std::size_t i=0;i<sz2;i++)
6026     {
6027       DataArrayIdType *locDa=idsInPflPerType2[i];
6028       locDa->incrRef();
6029       idsInPflPerType[i]=locDa;
6030     }
6031   std::size_t sz=idsPerType2.size();
6032   idsPerType.resize(sz);
6033   for(std::size_t i=0;i<sz;i++)
6034     {
6035       DataArrayIdType *locDa=idsPerType2[i];
6036       locDa->incrRef();
6037       idsPerType[i]=locDa;
6038     }
6039 }
6040
6041 /*!
6042  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
6043  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
6044  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
6045  * 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.
6046  */
6047 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
6048 {
6049   checkFullyDefined();
6050   nM1LevMesh->checkFullyDefined();
6051   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
6052     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
6053   if(_coords!=nM1LevMesh->getCoords())
6054     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
6055   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
6056   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
6057   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
6058   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
6059   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
6060   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
6061   tmp->setConnectivity(tmp0,tmp1);
6062   tmp->renumberCells(ret0->begin(),false);
6063   revDesc=tmp->getNodalConnectivity();
6064   revDescIndx=tmp->getNodalConnectivityIndex();
6065   DataArrayIdType *ret=0;
6066   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
6067     {
6068       mcIdType tmp2;
6069       ret->getMaxValue(tmp2);
6070       ret->decrRef();
6071       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
6072       throw INTERP_KERNEL::Exception(oss.str());
6073     }
6074   nM1LevMeshIds=ret;
6075   //
6076   revDesc->incrRef();
6077   revDescIndx->incrRef();
6078   ret1->incrRef();
6079   ret0->incrRef();
6080   meshnM1Old2New=ret0;
6081   return ret1;
6082 }
6083
6084 /*!
6085  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
6086  * necessary for writing the mesh to MED file. Additionally returns a permutation array
6087  * in "Old to New" mode.
6088  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
6089  *          this array using decrRef() as it is no more needed.
6090  *  \throw If the nodal connectivity of cells is not defined.
6091  */
6092 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
6093 {
6094   checkConnectivityFullyDefined();
6095   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
6096   renumberCells(ret->begin(),false);
6097   return ret.retn();
6098 }
6099
6100 /*!
6101  * This methods checks that cells are sorted by their types.
6102  * This method makes asumption (no check) that connectivity is correctly set before calling.
6103  */
6104 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
6105 {
6106   checkFullyDefined();
6107   const mcIdType *conn=_nodal_connec->begin();
6108   const mcIdType *connI=_nodal_connec_index->begin();
6109   mcIdType nbOfCells=getNumberOfCells();
6110   std::set<INTERP_KERNEL::NormalizedCellType> types;
6111   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6112     {
6113       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6114       if(types.find(curType)!=types.end())
6115         return false;
6116       types.insert(curType);
6117       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6118     }
6119   return true;
6120 }
6121
6122 /*!
6123  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
6124  * The geometric type order is specified by MED file.
6125  *
6126  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
6127  */
6128 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
6129 {
6130   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6131 }
6132
6133 /*!
6134  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
6135  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
6136  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
6137  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
6138  */
6139 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6140 {
6141   checkFullyDefined();
6142   const mcIdType *conn=_nodal_connec->begin();
6143   const mcIdType *connI=_nodal_connec_index->begin();
6144   mcIdType nbOfCells=getNumberOfCells();
6145   if(nbOfCells==0)
6146     return true;
6147   mcIdType lastPos=-1;
6148   std::set<INTERP_KERNEL::NormalizedCellType> sg;
6149   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6150     {
6151       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6152       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
6153       if(isTypeExists!=orderEnd)
6154         {
6155           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
6156           if(pos<=lastPos)
6157             return false;
6158           lastPos=pos;
6159           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6160         }
6161       else
6162         {
6163           if(sg.find(curType)==sg.end())
6164             {
6165               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6166               sg.insert(curType);
6167             }
6168           else
6169             return false;
6170         }
6171     }
6172   return true;
6173 }
6174
6175 /*!
6176  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6177  * 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
6178  * 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'.
6179  */
6180 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6181 {
6182   checkConnectivityFullyDefined();
6183   mcIdType nbOfCells=getNumberOfCells();
6184   const mcIdType *conn=_nodal_connec->begin();
6185   const mcIdType *connI=_nodal_connec_index->begin();
6186   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6187   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6188   tmpa->alloc(nbOfCells,1);
6189   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6190   tmpb->fillWithZero();
6191   mcIdType *tmp=tmpa->getPointer();
6192   mcIdType *tmp2=tmpb->getPointer();
6193   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6194     {
6195       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6196       if(where!=orderEnd)
6197         {
6198           mcIdType pos=ToIdType(std::distance(orderBg,where));
6199           tmp2[pos]++;
6200           tmp[std::distance(connI,i)]=pos;
6201         }
6202       else
6203         {
6204           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6205           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6206           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6207           throw INTERP_KERNEL::Exception(oss.str());
6208         }
6209     }
6210   nbPerType=tmpb.retn();
6211   return tmpa.retn();
6212 }
6213
6214 /*!
6215  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6216  *
6217  * \return a new object containing the old to new correspondence.
6218  *
6219  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6220  */
6221 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6222 {
6223   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6224 }
6225
6226 /*!
6227  * 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.
6228  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6229  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6230  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6231  */
6232 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6233 {
6234   DataArrayIdType *nbPerType=0;
6235   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6236   nbPerType->decrRef();
6237   return tmpa->buildPermArrPerLevel();
6238 }
6239
6240 /*!
6241  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6242  * The number of cells remains unchanged after the call of this method.
6243  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6244  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6245  *
6246  * \return the array giving the correspondence old to new.
6247  */
6248 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6249 {
6250   checkFullyDefined();
6251   computeTypes();
6252   const mcIdType *conn=_nodal_connec->begin();
6253   const mcIdType *connI=_nodal_connec_index->begin();
6254   mcIdType nbOfCells=getNumberOfCells();
6255   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6256   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6257     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6258       {
6259         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6260         types.push_back(curType);
6261         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6262       }
6263   DataArrayIdType *ret=DataArrayIdType::New();
6264   ret->alloc(nbOfCells,1);
6265   mcIdType *retPtr=ret->getPointer();
6266   std::fill(retPtr,retPtr+nbOfCells,-1);
6267   mcIdType newCellId=0;
6268   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6269     {
6270       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6271         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6272           retPtr[std::distance(connI,i)]=newCellId++;
6273     }
6274   renumberCells(retPtr,false);
6275   return ret;
6276 }
6277
6278 /*!
6279  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6280  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6281  * This method makes asumption that connectivity is correctly set before calling.
6282  */
6283 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6284 {
6285   checkConnectivityFullyDefined();
6286   const mcIdType *conn=_nodal_connec->begin();
6287   const mcIdType *connI=_nodal_connec_index->begin();
6288   mcIdType nbOfCells=getNumberOfCells();
6289   std::vector<MEDCouplingUMesh *> ret;
6290   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6291     {
6292       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6293       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6294       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6295       mcIdType endCellId=ToIdType(std::distance(connI,i));
6296       mcIdType sz=endCellId-beginCellId;
6297       mcIdType *cells=new mcIdType[sz];
6298       for(mcIdType j=0;j<sz;j++)
6299         cells[j]=beginCellId+j;
6300       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6301       delete [] cells;
6302       ret.push_back(m);
6303     }
6304   return ret;
6305 }
6306
6307 /*!
6308  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6309  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6310  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6311  *
6312  * \return a newly allocated instance, that the caller must manage.
6313  * \throw If \a this contains more than one geometric type.
6314  * \throw If the nodal connectivity of \a this is not fully defined.
6315  * \throw If the internal data is not coherent.
6316  */
6317 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6318 {
6319   checkConnectivityFullyDefined();
6320   if(_types.size()!=1)
6321     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6322   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6323   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6324   ret->setCoords(getCoords());
6325   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6326   if(retC)
6327     {
6328       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6329       retC->setNodalConnectivity(c);
6330     }
6331   else
6332     {
6333       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6334       if(!retD)
6335         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6336       DataArrayIdType *c=0,*ci=0;
6337       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6338       MCAuto<DataArrayIdType> cs(c),cis(ci);
6339       retD->setNodalConnectivity(cs,cis);
6340     }
6341   return ret.retn();
6342 }
6343
6344 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6345 {
6346   checkConnectivityFullyDefined();
6347   if(_types.size()!=1)
6348     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6349   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6350   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6351   if(cm.isDynamic())
6352     {
6353       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6354       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6355       throw INTERP_KERNEL::Exception(oss.str());
6356     }
6357   mcIdType nbCells=getNumberOfCells();
6358   mcIdType typi=ToIdType(typ);
6359   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6360   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6361   mcIdType *outPtr=connOut->getPointer();
6362   const mcIdType *conn=_nodal_connec->begin();
6363   const mcIdType *connI=_nodal_connec_index->begin();
6364   nbNodesPerCell++;
6365   for(mcIdType i=0;i<nbCells;i++,connI++)
6366     {
6367       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6368         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6369       else
6370         {
6371           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 << ") !";
6372           throw INTERP_KERNEL::Exception(oss.str());
6373         }
6374     }
6375   return connOut.retn();
6376 }
6377
6378 /*!
6379  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6380  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6381  * \param nodalConn nodal connectivity
6382  * \param nodalConnIndex nodal connectivity indices
6383  */
6384 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6385 {
6386   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6387   checkConnectivityFullyDefined();
6388   if(_types.size()!=1)
6389     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6390   mcIdType nbCells=getNumberOfCells(),
6391            lgth=_nodal_connec->getNumberOfTuples();
6392   if(lgth<nbCells)
6393     throw INTERP_KERNEL::Exception(msg0);
6394   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6395   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6396   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6397   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6398   cip[0]=0;
6399   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6400     {
6401       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6402       mcIdType delta(stop-strt);
6403       if(delta>=1)
6404         {
6405           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6406             cp=std::copy(incp+strt,incp+stop,cp);
6407           else
6408             throw INTERP_KERNEL::Exception(msg0);
6409         }
6410       else
6411         throw INTERP_KERNEL::Exception(msg0);
6412       cip[1]=cip[0]+delta;
6413     }
6414   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6415 }
6416
6417 /*!
6418  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6419  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6420  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6421  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6422  * are not used here to avoid the build of big permutation array.
6423  *
6424  * \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
6425  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6426  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6427  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6428  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6429  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6430  * \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
6431  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6432  */
6433 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6434                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6435                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6436 {
6437   std::vector<const MEDCouplingUMesh *> ms2;
6438   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6439     if(*it)
6440       {
6441         (*it)->checkConnectivityFullyDefined();
6442         ms2.push_back(*it);
6443       }
6444   if(ms2.empty())
6445     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6446   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6447   int meshDim=ms2[0]->getMeshDimension();
6448   std::vector<const MEDCouplingUMesh *> m1ssm;
6449   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6450   //
6451   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6452   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6453   mcIdType fake=0,rk=0;
6454   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6455   ret1->alloc(0,1); ret2->alloc(0,1);
6456   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6457     {
6458       if(meshDim!=(*it)->getMeshDimension())
6459         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6460       if(refCoo!=(*it)->getCoords())
6461         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6462       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6463       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6464       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6465       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6466         {
6467           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6468           m1ssmSingleAuto.push_back(singleCell);
6469           m1ssmSingle.push_back(singleCell);
6470           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6471         }
6472     }
6473   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6474   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6475   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6476   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6477     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6478   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6479   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6480   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6481   return ret0.retn();
6482 }
6483
6484 /*!
6485  * This method returns a newly created DataArrayIdType instance.
6486  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6487  */
6488 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6489 {
6490   checkFullyDefined();
6491   const mcIdType *conn=_nodal_connec->begin();
6492   const mcIdType *connIndex=_nodal_connec_index->begin();
6493   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6494   for(const mcIdType *w=begin;w!=end;w++)
6495     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6496       ret->pushBackSilent(*w);
6497   return ret.retn();
6498 }
6499
6500 /*!
6501  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6502  * are in [0:getNumberOfCells())
6503  */
6504 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6505 {
6506   checkFullyDefined();
6507   const mcIdType *conn=_nodal_connec->begin();
6508   const mcIdType *connI=_nodal_connec_index->begin();
6509   mcIdType nbOfCells=getNumberOfCells();
6510   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6511   mcIdType *tmp=new mcIdType[nbOfCells];
6512   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6513     {
6514       mcIdType j=0;
6515       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6516         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6517           tmp[std::distance(connI,i)]=j++;
6518     }
6519   DataArrayIdType *ret=DataArrayIdType::New();
6520   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6521   ret->copyStringInfoFrom(*da);
6522   mcIdType *retPtr=ret->getPointer();
6523   const mcIdType *daPtr=da->begin();
6524   mcIdType nbOfElems=da->getNbOfElems();
6525   for(mcIdType k=0;k<nbOfElems;k++)
6526     retPtr[k]=tmp[daPtr[k]];
6527   delete [] tmp;
6528   return ret;
6529 }
6530
6531 /*!
6532  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6533  * This method \b works \b for mesh sorted by type.
6534  * cells whose ids is in 'idsPerGeoType' array.
6535  * This method conserves coords and name of mesh.
6536  */
6537 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6538 {
6539   std::vector<mcIdType> code=getDistributionOfTypes();
6540   std::size_t nOfTypesInThis=code.size()/3;
6541   mcIdType sz=0,szOfType=0;
6542   for(std::size_t i=0;i<nOfTypesInThis;i++)
6543     {
6544       if(code[3*i]!=type)
6545         sz+=code[3*i+1];
6546       else
6547         szOfType=code[3*i+1];
6548     }
6549   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6550     if(*work<0 || *work>=szOfType)
6551       {
6552         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6553         oss << ". It should be in [0," << szOfType << ") !";
6554         throw INTERP_KERNEL::Exception(oss.str());
6555       }
6556   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6557   mcIdType *idsPtr=idsTokeep->getPointer();
6558   mcIdType offset=0;
6559   for(std::size_t i=0;i<nOfTypesInThis;i++)
6560     {
6561       if(code[3*i]!=type)
6562         for(mcIdType j=0;j<code[3*i+1];j++)
6563           *idsPtr++=offset+j;
6564       else
6565         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
6566       offset+=code[3*i+1];
6567     }
6568   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6569   ret->copyTinyInfoFrom(this);
6570   return ret.retn();
6571 }
6572
6573 /*!
6574  * This method returns a vector of size 'this->getNumberOfCells()'.
6575  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6576  */
6577 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6578 {
6579   mcIdType ncell=getNumberOfCells();
6580   std::vector<bool> ret(ncell);
6581   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6582   const mcIdType *c=getNodalConnectivity()->begin();
6583   for(mcIdType i=0;i<ncell;i++)
6584     {
6585       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6586       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6587       ret[i]=cm.isQuadratic();
6588     }
6589   return ret;
6590 }
6591
6592 /*!
6593  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6594  */
6595 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6596 {
6597   if(other->getType()!=UNSTRUCTURED)
6598     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6599   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6600   return MergeUMeshes(this,otherC);
6601 }
6602
6603 /*!
6604  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6605  * computed by averaging coordinates of cell nodes, so this method is not a right
6606  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6607  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6608  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6609  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6610  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6611  *          components. The caller is to delete this array using decrRef() as it is
6612  *          no more needed.
6613  *  \throw If the coordinates array is not set.
6614  *  \throw If the nodal connectivity of cells is not defined.
6615  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6616  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6617  */
6618 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6619 {
6620   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6621   int spaceDim=getSpaceDimension();
6622   mcIdType nbOfCells=getNumberOfCells();
6623   ret->alloc(nbOfCells,spaceDim);
6624   ret->copyStringInfoFrom(*getCoords());
6625   double *ptToFill=ret->getPointer();
6626   const mcIdType *nodal=_nodal_connec->begin();
6627   const mcIdType *nodalI=_nodal_connec_index->begin();
6628   const double *coor=_coords->begin();
6629   for(mcIdType i=0;i<nbOfCells;i++)
6630     {
6631       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6632       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6633       ptToFill+=spaceDim;
6634     }
6635   return ret.retn();
6636 }
6637
6638
6639 /*!
6640  * See computeCellCenterOfMass().
6641  *  \param eps a precision for the detection of degenerated arc of circles.
6642  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6643  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6644  *          components. The caller is to delete this array using decrRef() as it is
6645  *          no more needed.
6646  *  \throw If the coordinates array is not set.
6647  *  \throw If the nodal connectivity of cells is not defined.
6648  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6649  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6650  */
6651 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6652 {
6653   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6654   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6655   return ret.retn();
6656 }
6657
6658
6659 /*!
6660  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6661  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6662  *
6663  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6664  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6665  *
6666  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6667  * \throw If \a this is not fully defined (coordinates and connectivity)
6668  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6669  */
6670 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6671 {
6672   checkFullyDefined();
6673   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6674   int spaceDim=getSpaceDimension();
6675   mcIdType nbOfCells=getNumberOfCells();
6676   mcIdType nbOfNodes=getNumberOfNodes();
6677   ret->alloc(nbOfCells,spaceDim);
6678   double *ptToFill=ret->getPointer();
6679   const mcIdType *nodal=_nodal_connec->begin();
6680   const mcIdType *nodalI=_nodal_connec_index->begin();
6681   const double *coor=_coords->begin();
6682   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6683     {
6684       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6685       std::fill(ptToFill,ptToFill+spaceDim,0.);
6686       if(type!=INTERP_KERNEL::NORM_POLYHED)
6687         {
6688           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6689             {
6690               if(*conn>=0 && *conn<nbOfNodes)
6691                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6692               else
6693                 {
6694                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6695                   throw INTERP_KERNEL::Exception(oss.str());
6696                 }
6697             }
6698           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6699           if(nbOfNodesInCell>0)
6700             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6701           else
6702             {
6703               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6704               throw INTERP_KERNEL::Exception(oss.str());
6705             }
6706         }
6707       else
6708         {
6709           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6710           s.erase(-1);
6711           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6712             {
6713               if(*it>=0 && *it<nbOfNodes)
6714                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6715               else
6716                 {
6717                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6718                   throw INTERP_KERNEL::Exception(oss.str());
6719                 }
6720             }
6721           if(!s.empty())
6722             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)s.size()));
6723           else
6724             {
6725               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6726               throw INTERP_KERNEL::Exception(oss.str());
6727             }
6728         }
6729     }
6730   return ret.retn();
6731 }
6732
6733 /*!
6734  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6735  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6736  * are specified via an array of cell ids.
6737  *  \warning Validity of the specified cell ids is not checked!
6738  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6739  *  \param [in] begin - an array of cell ids of interest.
6740  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6741  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6742  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6743  *          caller is to delete this array using decrRef() as it is no more needed.
6744  *  \throw If the coordinates array is not set.
6745  *  \throw If the nodal connectivity of cells is not defined.
6746  *
6747  *  \if ENABLE_EXAMPLES
6748  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6749  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6750  *  \endif
6751  */
6752 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6753 {
6754   DataArrayDouble *ret=DataArrayDouble::New();
6755   int spaceDim=getSpaceDimension();
6756   std::size_t nbOfTuple=std::distance(begin,end);
6757   ret->alloc(nbOfTuple,spaceDim);
6758   double *ptToFill=ret->getPointer();
6759   double *tmp=new double[spaceDim];
6760   const mcIdType *nodal=_nodal_connec->begin();
6761   const mcIdType *nodalI=_nodal_connec_index->begin();
6762   const double *coor=_coords->begin();
6763   for(const mcIdType *w=begin;w!=end;w++)
6764     {
6765       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6766       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6767       ptToFill+=spaceDim;
6768     }
6769   delete [] tmp;
6770   return ret;
6771 }
6772
6773 /*!
6774  * 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".
6775  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6776  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6777  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6778  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6779  *
6780  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6781  * \throw If spaceDim!=3 or meshDim!=2.
6782  * \throw If connectivity of \a this is invalid.
6783  * \throw If connectivity of a cell in \a this points to an invalid node.
6784  */
6785 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6786 {
6787   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6788   mcIdType nbOfCells=getNumberOfCells();
6789   mcIdType nbOfNodes(getNumberOfNodes());
6790   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6791     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6792   ret->alloc(nbOfCells,4);
6793   double *retPtr(ret->getPointer());
6794   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6795   const double *coor(_coords->begin());
6796   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6797     {
6798       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6799       if(nodalI[1]-nodalI[0]>=4)
6800         {
6801           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6802                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6803                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6804           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6805                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6806                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6807           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]};
6808           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]));
6809           for(int j=0;j<3;j++)
6810             {
6811               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6812               if(nodeId>=0 && nodeId<nbOfNodes)
6813                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6814               else
6815                 {
6816                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6817                   throw INTERP_KERNEL::Exception(oss.str());
6818                 }
6819             }
6820           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6821             {
6822               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6823               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6824             }
6825           else
6826             {
6827               if(nodalI[1]-nodalI[0]==4)
6828                 {
6829                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6830                   throw INTERP_KERNEL::Exception(oss.str());
6831                 }
6832               //
6833               double dd[3]={0.,0.,0.};
6834               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6835                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6836               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6837               std::transform(dd,dd+3,dd,std::bind(std::multiplies<double>(),std::placeholders::_1,1./(double)nbOfNodesInCell));
6838               std::copy(dd,dd+3,matrix+4*2);
6839               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6840               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6841             }
6842         }
6843       else
6844         {
6845           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6846           throw INTERP_KERNEL::Exception(oss.str());
6847         }
6848     }
6849   return ret.retn();
6850 }
6851
6852 /*!
6853  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6854  *
6855  */
6856 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6857 {
6858   if(!da)
6859     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6860   da->checkAllocated();
6861   std::string name(da->getName());
6862   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6863   if(name.empty())
6864     ret->setName("Mesh");
6865   ret->setCoords(da);
6866   mcIdType nbOfTuples(da->getNumberOfTuples());
6867   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6868   c->alloc(2*nbOfTuples,1);
6869   cI->alloc(nbOfTuples+1,1);
6870   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6871   *cip++=0;
6872   for(mcIdType i=0;i<nbOfTuples;i++)
6873     {
6874       *cp++=INTERP_KERNEL::NORM_POINT1;
6875       *cp++=i;
6876       *cip++=2*(i+1);
6877     }
6878   ret->setConnectivity(c,cI,true);
6879   return ret.retn();
6880 }
6881
6882 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6883 {
6884   if(!da)
6885     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6886   da->checkAllocated();
6887   std::string name(da->getName());
6888   MCAuto<MEDCouplingUMesh> ret;
6889   {
6890     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6891     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6892     arr->alloc(da->getNumberOfTuples());
6893     tmp->setCoordsAt(0,arr);
6894     ret=tmp->buildUnstructured();
6895   }
6896   ret->setCoords(da);
6897   if(name.empty())
6898     ret->setName("Mesh");
6899   else
6900     ret->setName(name);
6901   return ret;
6902 }
6903
6904 /*!
6905  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6906  * Cells and nodes of
6907  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6908  *  \param [in] mesh1 - the first mesh.
6909  *  \param [in] mesh2 - the second mesh.
6910  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6911  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6912  *          is no more needed.
6913  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6914  *  \throw If the coordinates array is not set in none of the meshes.
6915  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6916  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6917  */
6918 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6919 {
6920   std::vector<const MEDCouplingUMesh *> tmp(2);
6921   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6922   return MergeUMeshes(tmp);
6923 }
6924
6925 /*!
6926  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6927  * Cells and nodes of
6928  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6929  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6930  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6931  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6932  *          is no more needed.
6933  *  \throw If \a a.size() == 0.
6934  *  \throw If \a a[ *i* ] == NULL.
6935  *  \throw If the coordinates array is not set in none of the meshes.
6936  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6937  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6938  */
6939 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6940 {
6941   std::size_t sz=a.size();
6942   if(sz==0)
6943     return MergeUMeshesLL(a);
6944   for(std::size_t ii=0;ii<sz;ii++)
6945     if(!a[ii])
6946       {
6947         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6948         throw INTERP_KERNEL::Exception(oss.str());
6949       }
6950   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6951   std::vector< const MEDCouplingUMesh * > aa(sz);
6952   int spaceDim=-3;
6953   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6954     {
6955       const MEDCouplingUMesh *cur=a[i];
6956       const DataArrayDouble *coo=cur->getCoords();
6957       if(coo)
6958         spaceDim=int(coo->getNumberOfComponents());
6959     }
6960   if(spaceDim==-3)
6961     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6962   for(std::size_t i=0;i<sz;i++)
6963     {
6964       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6965       aa[i]=bb[i];
6966     }
6967   return MergeUMeshesLL(aa);
6968 }
6969
6970 /*!
6971  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6972  * dimension and sharing the node coordinates array.
6973  * All cells of the first mesh precede all cells of the second mesh
6974  * within the result mesh.
6975  *  \param [in] mesh1 - the first mesh.
6976  *  \param [in] mesh2 - the second mesh.
6977  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6978  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6979  *          is no more needed.
6980  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6981  *  \throw If the meshes do not share the node coordinates array.
6982  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6983  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6984  */
6985 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6986 {
6987   std::vector<const MEDCouplingUMesh *> tmp(2);
6988   tmp[0]=mesh1; tmp[1]=mesh2;
6989   return MergeUMeshesOnSameCoords(tmp);
6990 }
6991
6992 /*!
6993  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6994  * dimension and sharing the node coordinates array.
6995  * All cells of the *i*-th mesh precede all cells of the
6996  * (*i*+1)-th mesh within the result mesh.
6997  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6998  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6999  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7000  *          is no more needed.
7001  *  \throw If \a a.size() == 0.
7002  *  \throw If \a a[ *i* ] == NULL.
7003  *  \throw If the meshes do not share the node coordinates array.
7004  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7005  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7006  */
7007 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
7008 {
7009   if(meshes.empty())
7010     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
7011   for(std::size_t ii=0;ii<meshes.size();ii++)
7012     if(!meshes[ii])
7013       {
7014         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
7015         throw INTERP_KERNEL::Exception(oss.str());
7016       }
7017   const DataArrayDouble *coords=meshes.front()->getCoords();
7018   int meshDim=meshes.front()->getMeshDimension();
7019   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
7020   mcIdType meshLgth=0;
7021   mcIdType meshIndexLgth=0;
7022   for(;iter!=meshes.end();iter++)
7023     {
7024       if(coords!=(*iter)->getCoords())
7025         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
7026       if(meshDim!=(*iter)->getMeshDimension())
7027         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
7028       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
7029       meshIndexLgth+=(*iter)->getNumberOfCells();
7030     }
7031   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
7032   nodal->alloc(meshLgth,1);
7033   mcIdType *nodalPtr=nodal->getPointer();
7034   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
7035   nodalIndex->alloc(meshIndexLgth+1,1);
7036   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
7037   mcIdType offset=0;
7038   for(iter=meshes.begin();iter!=meshes.end();iter++)
7039     {
7040       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
7041       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
7042       mcIdType nbOfCells=(*iter)->getNumberOfCells();
7043       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
7044       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
7045       if(iter!=meshes.begin())
7046         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind(std::plus<mcIdType>(),std::placeholders::_1,offset));
7047       else
7048         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
7049       offset+=meshLgth2;
7050     }
7051   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
7052   ret->setName("merge");
7053   ret->setMeshDimension(meshDim);
7054   ret->setConnectivity(nodal,nodalIndex,true);
7055   ret->setCoords(coords);
7056   return ret;
7057 }
7058
7059 /*!
7060  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
7061  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
7062  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
7063  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
7064  * New" mode are returned for each input mesh.
7065  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
7066  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
7067  *          valid values [0,1,2], see zipConnectivityTraducer().
7068  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
7069  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
7070  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
7071  *          no more needed.
7072  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7073  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7074  *          is no more needed.
7075  *  \throw If \a meshes.size() == 0.
7076  *  \throw If \a meshes[ *i* ] == NULL.
7077  *  \throw If the meshes do not share the node coordinates array.
7078  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
7079  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
7080  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
7081  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
7082  */
7083 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
7084 {
7085   //All checks are delegated to MergeUMeshesOnSameCoords
7086   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
7087   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
7088   corr.resize(meshes.size());
7089   std::size_t nbOfMeshes=meshes.size();
7090   mcIdType offset=0;
7091   const mcIdType *o2nPtr=o2n->begin();
7092   for(std::size_t i=0;i<nbOfMeshes;i++)
7093     {
7094       DataArrayIdType *tmp=DataArrayIdType::New();
7095       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
7096       tmp->alloc(curNbOfCells,1);
7097       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
7098       offset+=curNbOfCells;
7099       tmp->setName(meshes[i]->getName());
7100       corr[i]=tmp;
7101     }
7102   return ret.retn();
7103 }
7104
7105 /*!
7106  * Makes all given meshes share the nodal connectivity array. The common connectivity
7107  * array is created by concatenating the connectivity arrays of all given meshes. All
7108  * the given meshes must be of the same space dimension but dimension of cells **can
7109  * differ**. This method is particularly useful in MEDLoader context to build a \ref
7110  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7111  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7112  *  \param [in,out] meshes - a vector of meshes to update.
7113  *  \throw If any of \a meshes is NULL.
7114  *  \throw If the coordinates array is not set in any of \a meshes.
7115  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7116  *  \throw If \a meshes are of different space dimension.
7117  */
7118 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
7119 {
7120   std::size_t sz=meshes.size();
7121   if(sz==0 || sz==1)
7122     return;
7123   std::vector< const DataArrayDouble * > coords(meshes.size());
7124   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
7125   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
7126     {
7127       if((*it))
7128         {
7129           (*it)->checkConnectivityFullyDefined();
7130           const DataArrayDouble *coo=(*it)->getCoords();
7131           if(coo)
7132             *it2=coo;
7133           else
7134             {
7135               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7136               oss << " has no coordinate array defined !";
7137               throw INTERP_KERNEL::Exception(oss.str());
7138             }
7139         }
7140       else
7141         {
7142           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
7143           oss << " is null !";
7144           throw INTERP_KERNEL::Exception(oss.str());
7145         }
7146     }
7147   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
7148   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
7149   mcIdType offset=(*it)->getNumberOfNodes();
7150   (*it++)->setCoords(res);
7151   for(;it!=meshes.end();it++)
7152     {
7153       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
7154       (*it)->setCoords(res);
7155       (*it)->shiftNodeNumbersInConn(offset);
7156       offset+=oldNumberOfNodes;
7157     }
7158 }
7159
7160 /*!
7161  * Merges nodes coincident with a given precision within all given meshes that share
7162  * the nodal connectivity array. The given meshes **can be of different** mesh
7163  * dimension. This method is particularly useful in MEDLoader context to build a \ref
7164  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7165  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7166  *  \param [in,out] meshes - a vector of meshes to update.
7167  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7168  *  \throw If any of \a meshes is NULL.
7169  *  \throw If the \a meshes do not share the same node coordinates array.
7170  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7171  */
7172 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7173 {
7174   if(meshes.empty())
7175     return ;
7176   std::set<const DataArrayDouble *> s;
7177   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7178     {
7179       if(*it)
7180         s.insert((*it)->getCoords());
7181       else
7182         {
7183           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 !";
7184           throw INTERP_KERNEL::Exception(oss.str());
7185         }
7186     }
7187   if(s.size()!=1)
7188     {
7189       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 !";
7190       throw INTERP_KERNEL::Exception(oss.str());
7191     }
7192   const DataArrayDouble *coo=*(s.begin());
7193   if(!coo)
7194     return;
7195   //
7196   DataArrayIdType *comm,*commI;
7197   coo->findCommonTuples(eps,-1,comm,commI);
7198   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7199   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7200   mcIdType newNbOfNodes;
7201   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7202   if(oldNbOfNodes==newNbOfNodes)
7203     return ;
7204   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7205   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7206     {
7207       (*it)->renumberNodesInConn(o2n->begin());
7208       (*it)->setCoords(newCoords);
7209     }
7210 }
7211
7212
7213 /*!
7214  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7215  */
7216 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7217 {
7218   std::size_t i, ip1;
7219   double v[3]={0.,0.,0.};
7220   std::size_t sz=std::distance(begin,end);
7221   if(!isQuadratic)
7222     for(i=0;i<sz;i++)
7223       {
7224         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7225         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7226         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];
7227         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7228         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7229       }
7230   else
7231     {
7232       // Same algorithm as above but also using intermediate quadratic points.
7233       // (taking only linear points might lead to issues if the linearized version of the
7234       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7235       std::size_t hsz = sz/2;
7236       for(std::size_t j=0;j<sz;j++)
7237         {
7238           if (j%2)  // current point i is quadratic, next point i+1 is standard
7239             {
7240               i = hsz+(j-1)/2;
7241               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7242             }
7243           else      // current point i is standard, next point i+1 is quadratic
7244             {
7245               i = j/2;
7246               ip1 = j/2+hsz;
7247             }
7248           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7249           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7250           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7251         }
7252     }
7253   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7254   return (ret>0.);
7255 }
7256
7257 /*!
7258  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7259  */
7260 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7261 {
7262   std::vector<std::pair<mcIdType,mcIdType> > edges;
7263   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7264   const mcIdType *bgFace=begin;
7265   for(std::size_t i=0;i<nbOfFaces;i++)
7266     {
7267       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7268       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7269       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7270         {
7271           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7272           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7273             return false;
7274           edges.push_back(p1);
7275         }
7276       bgFace=endFace+1;
7277     }
7278   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7279 }
7280
7281 /*!
7282  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7283  */
7284 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7285 {
7286   double vec0[3],vec1[3];
7287   std::size_t sz=std::distance(begin,end);
7288   if(sz%2!=0)
7289     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7290   mcIdType nbOfNodes=ToIdType(sz/2);
7291   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7292   const double *pt0=coords+3*begin[0];
7293   const double *pt1=coords+3*begin[nbOfNodes];
7294   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7295   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7296 }
7297
7298 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7299 {
7300   std::size_t sz=std::distance(begin,end);
7301   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7302   std::size_t nbOfNodes(sz/2);
7303   std::copy(begin,end,(mcIdType *)tmp);
7304   for(std::size_t j=1;j<nbOfNodes;j++)
7305     {
7306       begin[j]=tmp[nbOfNodes-j];
7307       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7308     }
7309 }
7310
7311 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7312 {
7313   std::size_t sz=std::distance(begin,end);
7314   if(sz!=4)
7315     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7316   double vec0[3],vec1[3];
7317   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7318   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];
7319   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;
7320 }
7321
7322 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7323 {
7324   std::size_t sz=std::distance(begin,end);
7325   if(sz!=5)
7326     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7327   double vec0[3];
7328   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7329   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7330   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7331 }
7332
7333 /*!
7334  * 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 )
7335  * 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
7336  * a 2D space.
7337  *
7338  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7339  * \param [in] coords the coordinates with nb of components exactly equal to 3
7340  * \param [in] index begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7341  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7342  */
7343 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7344                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7345 {
7346   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7347   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7348   double *vPtr=v->getPointer();
7349   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7350   double *pPtr=p->getPointer();
7351   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7352   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7353   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7354     {
7355       mcIdType face = e_f[e_fi[index] + i];
7356       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7357       // to differentiate faces going to different cells:
7358       pPtr++, *pPtr = 0;
7359       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7360         *pPtr += FromIdType<double>(f_e[j]);
7361     }
7362   pPtr=p->getPointer(); vPtr=v->getPointer();
7363   DataArrayIdType *comm1=0,*commI1=0;
7364   v->findCommonTuples(eps,-1,comm1,commI1);
7365   for (mcIdType i = 0; i < nbFaces; i++)
7366     if (comm1->findIdFirstEqual(i) < 0)
7367       {
7368         comm1->pushBackSilent(i);
7369         commI1->pushBackSilent(comm1->getNumberOfTuples());
7370       }
7371   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7372   const mcIdType *comm1Ptr=comm1->begin();
7373   const mcIdType *commI1Ptr=commI1->begin();
7374   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7375   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7376   //
7377   for(mcIdType i=0;i<nbOfGrps1;i++)
7378     {
7379       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7380       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7381       DataArrayIdType *comm2=0,*commI2=0;
7382       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7383       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7384         if (comm2->findIdFirstEqual(j) < 0)
7385           {
7386             comm2->pushBackSilent(j);
7387             commI2->pushBackSilent(comm2->getNumberOfTuples());
7388           }
7389       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7390       const mcIdType *comm2Ptr=comm2->begin();
7391       const mcIdType *commI2Ptr=commI2->begin();
7392       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7393       for(mcIdType j=0;j<nbOfGrps2;j++)
7394         {
7395           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7396             {
7397               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7398               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7399               res->pushBackSilent(-1);
7400             }
7401           else
7402             {
7403               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7404               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7405               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7406               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7407               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7408               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7409               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7410               const mcIdType *idsNodePtr=idsNode->begin();
7411               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];
7412               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7413               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7414               if(std::abs(norm)>eps)
7415                 {
7416                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7417                   mm3->rotate(center,vec,angle);
7418                 }
7419               mm3->changeSpaceDimension(2);
7420               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7421               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7422               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7423               mcIdType nbOfCells=mm4->getNumberOfCells();
7424               for(mcIdType k=0;k<nbOfCells;k++)
7425                 {
7426                   int l=0;
7427                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7428                     res->pushBackSilent(idsNodePtr[*work]);
7429                   res->pushBackSilent(-1);
7430                 }
7431             }
7432         }
7433     }
7434   res->popBackSilent();
7435 }
7436
7437 /*!
7438  * 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
7439  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7440  *
7441  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7442  * \param [in] coords coordinates expected to have 3 components.
7443  * \param [in] begin start of the nodal connectivity of the face.
7444  * \param [in] end end of the nodal connectivity (excluded) of the face.
7445  * \param [out] v the normalized vector of size 3
7446  * \param [out] p the pos of plane
7447  */
7448 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7449 {
7450   std::size_t nbPoints=std::distance(begin,end);
7451   if(nbPoints<3)
7452     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7453   double vec[3]={0.,0.,0.};
7454   std::size_t j=0;
7455   bool refFound=false;
7456   for(;j<nbPoints-1 && !refFound;j++)
7457     {
7458       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7459       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7460       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7461       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7462       if(norm>eps)
7463         {
7464           refFound=true;
7465           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7466         }
7467     }
7468   for(std::size_t i=j;i<nbPoints-1;i++)
7469     {
7470       double curVec[3];
7471       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7472       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7473       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7474       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7475       if(norm<eps)
7476         continue;
7477       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7478       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];
7479       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7480       if(norm>eps)
7481         {
7482           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7483           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7484           return ;
7485         }
7486     }
7487   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7488 }
7489
7490 /*!
7491  * This method tries to obtain a well oriented polyhedron.
7492  * If the algorithm fails, an exception will be thrown.
7493  */
7494 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7495 {
7496   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7497   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7498   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7499   isPerm[0]=true;
7500   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7501   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7502   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7503   //
7504   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7505     {
7506       bgFace=begin;
7507       std::size_t smthChanged=0;
7508       for(std::size_t i=0;i<nbOfFaces;i++)
7509         {
7510           endFace=std::find(bgFace+1,end,-1);
7511           nbOfEdgesInFace=std::distance(bgFace,endFace);
7512           if(!isPerm[i])
7513             {
7514               bool b=false;
7515               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7516                 {
7517                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7518                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7519                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7520                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7521                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7522                 }
7523               if(isPerm[i])
7524                 {
7525                   if(!b)
7526                     std::reverse(bgFace+1,endFace);
7527                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7528                     {
7529                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7530                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7531                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7532                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7533                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7534                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7535                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7536                       if(it!=edgesOK.end())
7537                         {
7538                           edgesOK.erase(it);
7539                           edgesFinished.push_back(p1);
7540                         }
7541                       else
7542                         edgesOK.push_back(p1);
7543                     }
7544                 }
7545             }
7546           bgFace=endFace+1;
7547         }
7548       if(smthChanged==0)
7549         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7550     }
7551   if(!edgesOK.empty())
7552     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7553   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7554     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7555       bgFace=begin;
7556       for(std::size_t i=0;i<nbOfFaces;i++)
7557         {
7558           endFace=std::find(bgFace+1,end,-1);
7559           std::reverse(bgFace+1,endFace);
7560           bgFace=endFace+1;
7561         }
7562     }
7563 }
7564
7565
7566 /*!
7567  * This method makes the assumption spacedimension == meshdimension == 2.
7568  * This method works only for linear cells.
7569  *
7570  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7571  */
7572 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7573 {
7574   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7575     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7576   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7577   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7578   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7579   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7580   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7581   mcIdType nbCells=skin->getNumberOfCells();
7582   if(nbCells==nbOfNodesExpected)
7583     return buildUnionOf2DMeshLinear(skin,n2o);
7584   else if(2*nbCells==nbOfNodesExpected)
7585     return buildUnionOf2DMeshQuadratic(skin,n2o);
7586   else
7587     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7588 }
7589
7590 /*!
7591  * This method makes the assumption spacedimension == meshdimension == 3.
7592  * This method works only for linear cells.
7593  *
7594  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7595  */
7596 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7597 {
7598   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7599     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7600   MCAuto<MEDCouplingUMesh> m=computeSkin();
7601   const mcIdType *conn=m->getNodalConnectivity()->begin();
7602   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7603   mcIdType nbOfCells=m->getNumberOfCells();
7604   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7605   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7606   if(nbOfCells<1)
7607     return ret.retn();
7608   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7609   for(mcIdType i=1;i<nbOfCells;i++)
7610     {
7611       *work++=-1;
7612       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7613     }
7614   return ret.retn();
7615 }
7616
7617 /*!
7618  * \brief Creates a graph of cell neighbors
7619  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7620  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7621  *  For example
7622  *  - index:  0 3 5 6 6
7623  *  - value:  1 2 3 2 3 3
7624  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7625  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7626  */
7627 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7628 {
7629   checkConnectivityFullyDefined();
7630
7631   int meshDim = this->getMeshDimension();
7632   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7633   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7634   this->getReverseNodalConnectivity(revConn,indexr);
7635   const mcIdType* indexr_ptr=indexr->begin();
7636   const mcIdType* revConn_ptr=revConn->begin();
7637
7638   const MEDCoupling::DataArrayIdType* index;
7639   const MEDCoupling::DataArrayIdType* conn;
7640   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7641   index=this->getNodalConnectivityIndex();
7642   mcIdType nbCells=this->getNumberOfCells();
7643   const mcIdType* index_ptr=index->begin();
7644   const mcIdType* conn_ptr=conn->begin();
7645
7646   //creating graph arcs (cell to cell relations)
7647   //arcs are stored in terms of (index,value) notation
7648   // 0 3 5 6 6
7649   // 1 2 3 2 3 3
7650   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7651   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7652
7653   //warning here one node have less than or equal effective number of cell with it
7654   //but cell could have more than effective nodes
7655   //because other equals nodes in other domain (with other global inode)
7656   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7657   std::vector <mcIdType> cell2cell;
7658   cell2cell.reserve(3*nbCells);
7659
7660   for (mcIdType icell=0; icell<nbCells;icell++)
7661     {
7662       std::map<mcIdType,mcIdType > counter;
7663       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7664         {
7665           mcIdType inode=conn_ptr[iconn];
7666           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7667             {
7668               mcIdType icell2=revConn_ptr[iconnr];
7669               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7670               if (iter!=counter.end()) (iter->second)++;
7671               else counter.insert(std::make_pair(icell2,1));
7672             }
7673         }
7674       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7675            iter!=counter.end(); iter++)
7676         if (iter->second >= meshDim)
7677           {
7678             cell2cell_index[icell+1]++;
7679             cell2cell.push_back(iter->first);
7680           }
7681     }
7682   indexr->decrRef();
7683   revConn->decrRef();
7684   cell2cell_index[0]=0;
7685   for (mcIdType icell=0; icell<nbCells;icell++)
7686     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7687
7688   //filling up index and value to create skylinearray structure
7689   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7690   return array;
7691 }
7692
7693
7694 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7695 {
7696   mcIdType nbOfCells=getNumberOfCells();
7697   if(nbOfCells<=0)
7698     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7699   ofs << "  <" << getVTKDataSetType() << ">\n";
7700   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7701   ofs << "      <PointData>\n" << pointData << std::endl;
7702   ofs << "      </PointData>\n";
7703   ofs << "      <CellData>\n" << cellData << std::endl;
7704   ofs << "      </CellData>\n";
7705   ofs << "      <Points>\n";
7706   if(getSpaceDimension()==3)
7707     _coords->writeVTK(ofs,8,"Points",byteData);
7708   else
7709     {
7710       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7711       coo->writeVTK(ofs,8,"Points",byteData);
7712     }
7713   ofs << "      </Points>\n";
7714   ofs << "      <Cells>\n";
7715   const mcIdType *cPtr=_nodal_connec->begin();
7716   const mcIdType *cIPtr=_nodal_connec_index->begin();
7717   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7718   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7719   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7720   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7721   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7722   mcIdType szFaceOffsets=0,szConn=0;
7723   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7724     {
7725       *w2=cPtr[cIPtr[i]];
7726       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7727         {
7728           *w1=-1;
7729           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7730           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7731         }
7732       else
7733         {
7734           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7735           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7736           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7737           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7738           w4=std::copy(c.begin(),c.end(),w4);
7739         }
7740     }
7741   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7742   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7743     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7744   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7745   types->writeVTK(ofs,8,"UInt8","types",byteData);
7746   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7747   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7748   if(szFaceOffsets!=0)
7749     {//presence of Polyhedra
7750       connectivity->reAlloc(szConn);
7751       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7752       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7753       w1=faces->getPointer();
7754       for(mcIdType i=0;i<nbOfCells;i++)
7755         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7756           {
7757             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7758             *w1++=nbFaces;
7759             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7760             for(mcIdType j=0;j<nbFaces;j++)
7761               {
7762                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7763                 *w1++=ToIdType(std::distance(w6,w5));
7764                 w1=std::copy(w6,w5,w1);
7765                 w6=w5+1;
7766               }
7767           }
7768       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7769     }
7770   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7771   ofs << "      </Cells>\n";
7772   ofs << "    </Piece>\n";
7773   ofs << "  </" << getVTKDataSetType() << ">\n";
7774 }
7775
7776 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7777 {
7778   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7779   if(_mesh_dim==-2)
7780     { stream << " Not set !"; return ; }
7781   stream << " Mesh dimension : " << _mesh_dim << ".";
7782   if(_mesh_dim==-1)
7783     return ;
7784   if(!_coords)
7785     { stream << " No coordinates set !"; return ; }
7786   if(!_coords->isAllocated())
7787     { stream << " Coordinates set but not allocated !"; return ; }
7788   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7789   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7790   if(!_nodal_connec_index)
7791     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7792   if(!_nodal_connec_index->isAllocated())
7793     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7794   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7795   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7796   if(cpt!=1 || lgth<1)
7797     return ;
7798   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7799 }
7800
7801 std::string MEDCouplingUMesh::getVTKDataSetType() const
7802 {
7803   return std::string("UnstructuredGrid");
7804 }
7805
7806 std::string MEDCouplingUMesh::getVTKFileExtension() const
7807 {
7808   return std::string("vtu");
7809 }
7810
7811
7812
7813 /**
7814  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7815  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7816  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7817  * The caller is to deal with the resulting DataArrayIdType.
7818  *  \throw If the coordinate array is not set.
7819  *  \throw If the nodal connectivity of the cells is not defined.
7820  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7821  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7822  *
7823  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7824  */
7825 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7826 {
7827   checkFullyDefined();
7828   if(getMeshDimension()!=1)
7829     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7830
7831   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7832   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7833   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7834   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7835   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7836   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7837   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7838   const mcIdType * dsi(_dsi->begin());
7839   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7840   m_points=0;
7841   if (dsii->getNumberOfTuples())
7842     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7843
7844   mcIdType nc=getNumberOfCells();
7845   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7846   result->alloc(nc,1);
7847
7848   // set of edges not used so far
7849   std::set<mcIdType> edgeSet;
7850   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7851
7852   mcIdType startSeg=0;
7853   mcIdType newIdx=0;
7854   // while we have points with only one neighbor segments
7855   do
7856     {
7857       std::list<mcIdType> linePiece;
7858       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7859       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7860         {
7861           // Fill the list forward (resp. backward) from the start segment:
7862           mcIdType activeSeg = startSeg;
7863           mcIdType prevPointId = -20;
7864           mcIdType ptId;
7865           while (!edgeSet.empty())
7866             {
7867               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7868                 {
7869                   if (direction==0)
7870                     linePiece.push_back(activeSeg);
7871                   else
7872                     linePiece.push_front(activeSeg);
7873                   edgeSet.erase(activeSeg);
7874                 }
7875
7876               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7877               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7878               if (dsi[ptId] == 1) // hitting the end of the line
7879                 break;
7880
7881               prevPointId = ptId;
7882               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7883               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7884
7885               //for piecewise meshes made up of closed parts
7886               bool segmentAlreadyTreated = (std::find(linePiece.begin(), linePiece.end(), activeSeg) != linePiece.end());
7887               if(segmentAlreadyTreated)
7888                 break;
7889             }
7890         }
7891       // Done, save final piece into DA:
7892       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7893       newIdx += ToIdType(linePiece.size());
7894
7895       // identify next valid start segment (one which is not consumed)
7896       if(!edgeSet.empty())
7897         startSeg = *(edgeSet.begin());
7898
7899     }
7900   while (!edgeSet.empty());
7901   return result.retn();
7902 }
7903
7904 /**
7905  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7906  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7907  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7908  * a minimal creation of new nodes is wanted.
7909  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7910  * nodes if a SEG3 is split without information of middle.
7911  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7912  * avoid to have a non conform mesh.
7913  *
7914  * \return mcIdType - the number of new nodes created (in most of cases 0).
7915  *
7916  * \throw If \a this is not coherent.
7917  * \throw If \a this has not spaceDim equal to 2.
7918  * \throw If \a this has not meshDim equal to 2.
7919  * \throw If some subcells needed to be split are orphan.
7920  * \sa MEDCouplingUMesh::conformize2D
7921  */
7922 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7923 {
7924   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7925     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7926   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7927   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7928     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7929   if(midOpt==0 && midOptI==0)
7930     {
7931       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7932       return 0;
7933     }
7934   else if(midOpt!=0 && midOptI!=0)
7935     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7936   else
7937     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7938 }
7939
7940 /*!
7941  * 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
7942  * 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
7943  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7944  * 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
7945  * 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.
7946  *
7947  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7948  */
7949 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7950 {
7951   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7952   if(sz>=4)
7953     {
7954       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7955       if(cm.getDimension()==2)
7956         {
7957           const mcIdType *node=nodalConnBg+1;
7958           mcIdType startNode=*node++;
7959           double refX=coords[2*startNode];
7960           for(;node!=nodalConnEnd;node++)
7961             {
7962               if(coords[2*(*node)]<refX)
7963                 {
7964                   startNode=*node;
7965                   refX=coords[2*startNode];
7966                 }
7967             }
7968           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7969           refX=1e300;
7970           double tmp1;
7971           double tmp2[2];
7972           double angle0=-M_PI/2;
7973           //
7974           mcIdType nextNode=-1;
7975           mcIdType prevNode=-1;
7976           double resRef;
7977           double angleNext=0.;
7978           while(nextNode!=startNode)
7979             {
7980               nextNode=-1;
7981               resRef=1e300;
7982               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7983                 {
7984                   if(*node!=tmpOut.back() && *node!=prevNode)
7985                     {
7986                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7987                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7988                       double res;
7989                       if(angleM<=angle0)
7990                         res=angle0-angleM;
7991                       else
7992                         res=angle0-angleM+2.*M_PI;
7993                       if(res<resRef)
7994                         {
7995                           nextNode=*node;
7996                           resRef=res;
7997                           angleNext=angleM;
7998                         }
7999                     }
8000                 }
8001               if(nextNode!=startNode)
8002                 {
8003                   angle0=angleNext-M_PI;
8004                   if(angle0<-M_PI)
8005                     angle0+=2*M_PI;
8006                   prevNode=tmpOut.back();
8007                   tmpOut.push_back(nextNode);
8008                 }
8009             }
8010           std::vector<mcIdType> tmp3(2*(sz-1));
8011           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
8012           std::copy(nodalConnBg+1,nodalConnEnd,it);
8013           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
8014             {
8015               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8016               return false;
8017             }
8018           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
8019             {
8020               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
8021               return false;
8022             }
8023           else
8024             {
8025               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
8026               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
8027               return true;
8028             }
8029         }
8030       else
8031         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8032     }
8033   else
8034     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
8035 }
8036
8037 /*!
8038  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8039  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8040  * 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]].
8041  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8042  * A negative value in \b arrIn means that it is ignored.
8043  * 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.
8044  *
8045  * \param [in] arrIn arr origin array from which the extraction will be done.
8046  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8047  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8048  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
8049  */
8050 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8051 {
8052   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
8053   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
8054 }
8055
8056 /*!
8057  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
8058  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
8059  * 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]].
8060  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
8061  * A negative value in \b arrIn means that it is ignored.
8062  * 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.
8063  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
8064  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
8065  * \param [in] arrIn arr origin array from which the extraction will be done.
8066  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
8067  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
8068  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
8069  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
8070  * \sa MEDCouplingUMesh::partitionBySpreadZone
8071  */
8072 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
8073 {
8074   nbOfDepthPeelingPerformed=0;
8075   if(!arrIndxIn)
8076     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
8077   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
8078   if(nbOfTuples<=0)
8079     {
8080       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
8081       return ret;
8082     }
8083   //
8084   std::vector<bool> fetched(nbOfTuples,false);
8085   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
8086 }
8087
8088
8089
8090 /*!
8091  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
8092  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
8093  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
8094  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
8095  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
8096  *
8097  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
8098  */
8099 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
8100 {
8101   checkFullyDefined();
8102   int mdim=getMeshDimension();
8103   int spaceDim=getSpaceDimension();
8104   if(mdim!=spaceDim)
8105     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
8106   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
8107   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
8108   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
8109   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
8110   ret->setCoords(getCoords());
8111   ret->allocateCells(ToIdType(partition.size()));
8112   //
8113   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
8114     {
8115       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
8116       MCAuto<DataArrayIdType> cell;
8117       switch(mdim)
8118       {
8119         case 2:
8120           cell=tmp->buildUnionOf2DMesh();
8121           break;
8122         case 3:
8123           cell=tmp->buildUnionOf3DMesh();
8124           break;
8125         default:
8126           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
8127       }
8128
8129       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
8130     }
8131   //
8132   ret->finishInsertingCells();
8133   return ret.retn();
8134 }
8135
8136 /*!
8137  * This method partitions \b this into contiguous zone.
8138  * This method only needs a well defined connectivity. Coordinates are not considered here.
8139  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
8140  */
8141 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
8142 {
8143   DataArrayIdType *neigh=0,*neighI=0;
8144   computeNeighborsOfCells(neigh,neighI);
8145   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
8146   return PartitionBySpreadZone(neighAuto,neighIAuto);
8147 }
8148
8149 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
8150 {
8151   if(!arrIn || !arrIndxIn)
8152     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
8153   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
8154   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
8155   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
8156     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
8157   mcIdType nbOfCellsCur(nbOfTuples-1);
8158   std::vector<DataArrayIdType *> ret;
8159   if(nbOfCellsCur<=0)
8160     return ret;
8161   std::vector<bool> fetchedCells(nbOfCellsCur,false);
8162   std::vector< MCAuto<DataArrayIdType> > ret2;
8163   mcIdType seed=0;
8164   while(seed<nbOfCellsCur)
8165     {
8166       mcIdType nbOfPeelPerformed=0;
8167       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
8168       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
8169     }
8170   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8171     ret.push_back((*it).retn());
8172   return ret;
8173 }
8174
8175 /*!
8176  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8177  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8178  *
8179  * \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.
8180  * \return a newly allocated DataArrayIdType to be managed by the caller.
8181  * \throw In case of \a code has not the right format (typically of size 3*n)
8182  */
8183 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8184 {
8185   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8186   std::size_t nb=code.size()/3;
8187   if(code.size()%3!=0)
8188     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8189   ret->alloc(nb,2);
8190   mcIdType *retPtr=ret->getPointer();
8191   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8192     {
8193       retPtr[0]=code[3*i+2];
8194       retPtr[1]=code[3*i+2]+code[3*i+1];
8195     }
8196   return ret.retn();
8197 }
8198
8199 /*!
8200  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8201  * All cells in \a this are expected to be linear 3D cells.
8202  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8203  * It leads to an increase to number of cells.
8204  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8205  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8206  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8207  *
8208  * \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.
8209  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8210  * \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.
8211  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8212  *          an id of old cell producing it. The caller is to delete this array using
8213  *         decrRef() as it is no more needed.
8214  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8215  *
8216  * \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
8217  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8218  *
8219  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8220  * \throw If \a this is not fully constituted with linear 3D cells.
8221  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8222  */
8223 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8224 {
8225   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8226   checkConnectivityFullyDefined();
8227   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8228     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8229   mcIdType nbOfCells=getNumberOfCells();
8230   mcIdType nbNodes(getNumberOfNodes());
8231   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8232   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8233   mcIdType *retPt(ret->getPointer());
8234   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8235   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8236   const mcIdType *oldc(_nodal_connec->begin());
8237   const mcIdType *oldci(_nodal_connec_index->begin());
8238   const double *coords(_coords->begin());
8239   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8240     {
8241       std::vector<mcIdType> a; std::vector<double> b;
8242       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8243       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8244       const mcIdType *aa(&a[0]);
8245       if(!b.empty())
8246         {
8247           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8248             if(*it<0)
8249               *it=(-(*(it))-1+nbNodes);
8250           addPts->insertAtTheEnd(b.begin(),b.end());
8251           nbNodes+=ToIdType(b.size()/3);
8252         }
8253       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8254         newConn->insertAtTheEnd(aa,aa+4);
8255     }
8256   if(!addPts->empty())
8257     {
8258       addPts->rearrange(3);
8259       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8260       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8261       ret0->setCoords(addPts);
8262     }
8263   else
8264     {
8265       nbOfAdditionalPoints=0;
8266       ret0->setCoords(getCoords());
8267     }
8268   ret0->setNodalConnectivity(newConn);
8269   //
8270   ret->computeOffsetsFull();
8271   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8272   return ret0.retn();
8273 }
8274
8275 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8276     _own_cell(true),_cell_id(-1),_nb_cell(0)
8277 {
8278   if(mesh)
8279     {
8280       mesh->incrRef();
8281       _nb_cell=mesh->getNumberOfCells();
8282     }
8283 }
8284
8285 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8286 {
8287   if(_mesh)
8288     _mesh->decrRef();
8289   if(_own_cell)
8290     delete _cell;
8291 }
8292
8293 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8294     _own_cell(false),_cell_id(bg-1),
8295     _nb_cell(end)
8296 {
8297   if(mesh)
8298     mesh->incrRef();
8299 }
8300
8301 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8302 {
8303   _cell_id++;
8304   if(_cell_id<_nb_cell)
8305     {
8306       _cell->next();
8307       return _cell;
8308     }
8309   else
8310     return 0;
8311 }
8312
8313 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8314 {
8315   if(_mesh)
8316     _mesh->incrRef();
8317 }
8318
8319 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8320 {
8321   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8322 }
8323
8324 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8325 {
8326   if(_mesh)
8327     _mesh->decrRef();
8328 }
8329
8330 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8331     _itc(itc),
8332     _bg(bg),_end(end)
8333 {
8334   if(_mesh)
8335     _mesh->incrRef();
8336 }
8337
8338 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8339 {
8340   if(_mesh)
8341     _mesh->decrRef();
8342 }
8343
8344 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8345 {
8346   return _type;
8347 }
8348
8349 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8350 {
8351   return _end-_bg;
8352 }
8353
8354 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8355 {
8356   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8357 }
8358
8359 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8360 {
8361   if(mesh)
8362     {
8363       mesh->incrRef();
8364       _nb_cell=mesh->getNumberOfCells();
8365     }
8366 }
8367
8368 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8369 {
8370   if(_mesh)
8371     _mesh->decrRef();
8372   delete _cell;
8373 }
8374
8375 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8376 {
8377   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8378   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8379   if(_cell_id<_nb_cell)
8380     {
8381       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8382       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8383       mcIdType startId=_cell_id;
8384       _cell_id+=nbOfElems;
8385       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8386     }
8387   else
8388     return 0;
8389 }
8390
8391 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8392 {
8393   if(mesh)
8394     {
8395       _conn=mesh->getNodalConnectivity()->getPointer();
8396       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8397     }
8398 }
8399
8400 void MEDCouplingUMeshCell::next()
8401 {
8402   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8403     {
8404       _conn+=_conn_lgth;
8405       _conn_indx++;
8406     }
8407   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8408 }
8409
8410 std::string MEDCouplingUMeshCell::repr() const
8411 {
8412   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8413     {
8414       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8415       oss << " : ";
8416       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8417       return oss.str();
8418     }
8419   else
8420     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8421 }
8422
8423 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8424 {
8425   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8426     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8427   else
8428     return INTERP_KERNEL::NORM_ERROR;
8429 }
8430
8431 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8432 {
8433   lgth=_conn_lgth;
8434   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8435     return _conn;
8436   else
8437     return 0;
8438 }
8439
8440 /// @cond INTERNAL
8441
8442 namespace MEDCouplingImpl
8443 {
8444   const mcIdType theUndefID = std::numeric_limits< mcIdType >::max(); //!< undefined cell id
8445
8446   //================================================================================
8447   /*!
8448    * \brief Encode a cell id and a mesh index into a code
8449    *  \param [in] id - cell id
8450    *  \param [in] iMesh - mesh index [0,1]
8451    *  \return mcIdType - code
8452    */
8453   //================================================================================
8454
8455   mcIdType encodeID( mcIdType id, int iMesh )
8456   {
8457     return ( id + 1 ) * ( iMesh ? -1 : 1 );
8458   }
8459   //================================================================================
8460   /*!
8461    * \brief Return cell id and mesh index by a given id
8462    *  \param [in] id - code of a cell in a mesh
8463    *  \param [out] iMesh - returned mesh index
8464    *  \return mcIdType - cell id
8465    */
8466   //================================================================================
8467
8468   mcIdType decodeID( mcIdType id, int& iMesh )
8469   {
8470     iMesh = ( id < 0 );
8471     return std::abs( id ) - 1;
8472   }
8473
8474   //================================================================================
8475   /*!
8476    * \brief return another face sharing two given nodes of a face edge
8477    *  \param [in] n0 - 1st node of the edge
8478    *  \param [in] n1 - 2nd node of the edge
8479    *  \param [in] inputFaceID - face including \a n0 andf \a n2
8480    *  \param [in] mesh - object and reference meshes
8481    *  \param [in] revNodal - reverse nodal connectivity of the two meshes
8482    *  \param [in] revNodalIndx - index of reverse nodal connectivity of the two meshes
8483    *  \param [out] facesByEdge - return another face including \a n0 andf \a n2
8484    *  \param [out] equalFaces - return faces equal to facesByEdge
8485    */
8486   //================================================================================
8487
8488   void getFacesOfEdge( mcIdType n0,
8489                        mcIdType n1,
8490                        mcIdType inputFaceID,
8491                        MEDCouplingUMesh* mesh[],
8492                        MCAuto<DataArrayIdType> revNodal[],
8493                        MCAuto<DataArrayIdType> revNodalIndx[],
8494                        std::vector< mcIdType >& facesByEdge,
8495                        std::vector< mcIdType >& equalFaces)
8496   {
8497     // find faces sharing the both nodes of edge
8498
8499     facesByEdge.clear();
8500     size_t prevNbF; // nb faces found in 0-th mesh
8501     for ( int iM = 0; iM < 2; ++iM )
8502       {
8503         const mcIdType * revInd = revNodalIndx[ iM ]->begin();
8504         const mcIdType * rev    = revNodal    [ iM ]->begin();
8505
8506         mcIdType nbRevFaces0 = revInd[ n0 + 1 ] - revInd[ n0 ];
8507         mcIdType nbRevFaces1 = revInd[ n1 + 1 ] - revInd[ n1 ];
8508
8509         prevNbF = facesByEdge.size();
8510         facesByEdge.resize( prevNbF + std::max( nbRevFaces0, nbRevFaces1 ));
8511
8512         auto it = std::set_intersection( rev + revInd[ n0 ],
8513                                          rev + revInd[ n0 ] + nbRevFaces0,
8514                                          rev + revInd[ n1 ],
8515                                          rev + revInd[ n1 ] + nbRevFaces1,
8516                                          facesByEdge.begin() + prevNbF );
8517         facesByEdge.resize( it - facesByEdge.begin() );
8518       }
8519
8520     // facesByEdge now contains at least the 'inputFaceID'
8521     // check if there are other faces
8522
8523     size_t nbF = facesByEdge.size();
8524     if ( nbF > 1 )
8525       {
8526         if ( prevNbF > 0 && prevNbF < nbF ) // faces found in both meshes
8527           {
8528             // remove from facesByEdge equal faces in different meshes
8529             const mcIdType *conn [2] = { mesh[0]->getNodalConnectivity()->getConstPointer(),
8530                                          mesh[1]->getNodalConnectivity()->getConstPointer() };
8531             const mcIdType *connI[2] = { mesh[0]->getNodalConnectivityIndex()->getConstPointer(),
8532                                          mesh[1]->getNodalConnectivityIndex()->getConstPointer() };
8533             for ( size_t i0 = 0; i0 < prevNbF; ++i0 )
8534               {
8535                 if ( facesByEdge[ i0 ] == theUndefID )
8536                   continue;
8537                 mcIdType objFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i0 ], 0 );
8538                 bool   isInputFace = ( objFaceID == inputFaceID );
8539
8540                 for ( size_t i1 = prevNbF; i1 < facesByEdge.size(); ++i1 )
8541                   {
8542                     if ( facesByEdge[ i1 ] == theUndefID )
8543                       continue;
8544
8545                     mcIdType f0 = facesByEdge[ i0 ];
8546                     mcIdType f1 = facesByEdge[ i1 ];
8547                     size_t nbNodes0 = connI[0][ f0 + 1 ] - connI[0][ f0 ] - 1;
8548                     size_t nbNodes1 = connI[1][ f1 + 1 ] - connI[1][ f1 ] - 1;
8549                     if ( nbNodes0 != nbNodes1 )
8550                       continue;
8551
8552                     const mcIdType * fConn0 = conn[0] + connI[0][ f0 ] + 1;
8553                     const mcIdType * fConn1 = conn[1] + connI[1][ f1 ] + 1;
8554                     if ( std::equal( fConn0, fConn0 + nbNodes0, fConn1 ))
8555                       {
8556                         // equal faces; remove an object one
8557                         mcIdType refFaceID = MEDCouplingImpl::encodeID( facesByEdge[ i1 ], 1 );
8558                         if ( refFaceID == inputFaceID )
8559                           isInputFace = true;
8560
8561                         if ( std::find( equalFaces.begin(),
8562                                         equalFaces.end(), objFaceID ) == equalFaces.end() )
8563                           equalFaces.push_back( objFaceID );
8564
8565                         facesByEdge[ i0 ] = theUndefID;
8566                         if ( isInputFace )
8567                           facesByEdge[ i1 ] = theUndefID;
8568                         break;
8569                       }
8570                   }
8571                 if ( isInputFace )
8572                   facesByEdge[ i0 ] = theUndefID;
8573               }
8574           }
8575       }
8576
8577     nbF = facesByEdge.size();
8578     for ( size_t i = 0; i < facesByEdge.size(); ++i )
8579       {
8580         if ( facesByEdge[ i ] != theUndefID )
8581           {
8582             facesByEdge[ i ] = MEDCouplingImpl::encodeID( facesByEdge[ i ], i >= prevNbF );
8583             if ( facesByEdge[ i ] == inputFaceID )
8584               facesByEdge[ i ] = theUndefID;
8585           }
8586         nbF -= ( facesByEdge[ i ] == theUndefID );
8587       }
8588
8589     if ( nbF > 1 )
8590       return; // non-manifold
8591
8592     if ( nbF < 1 )
8593       {
8594         facesByEdge.clear();
8595       }
8596     else // nbF == 1, set a found face first
8597       {
8598         if ( facesByEdge[ 0 ] == theUndefID )
8599           {
8600             for ( size_t i = 1; i < facesByEdge.size(); ++i )
8601               if ( facesByEdge[ i ] != theUndefID )
8602                 {
8603                   facesByEdge[ 0 ] = facesByEdge[ i ];
8604                   break;
8605                 }
8606           }
8607         facesByEdge.resize( 1 );
8608       }
8609     return;
8610   }
8611
8612   //================================================================================
8613   /*!
8614    * \brief Remove a face from nodal reversed connectivity
8615    *  \param [in] node - a node of the face
8616    *  \param [in] face - the face
8617    *  \param [in.out] revNodal - reverse nodal connectivity
8618    *  \param [in,out] revNodalIndx - reverse nodal connectivity index
8619    */
8620   //================================================================================
8621
8622   void removeFromRevNodal( mcIdType node,
8623                            mcIdType face,
8624                            MCAuto<DataArrayIdType>& revNodal,
8625                            MCAuto<DataArrayIdType>& revNodalIndx)
8626   {
8627     mcIdType* fBeg = revNodal->getPointer() + revNodalIndx->getIJ( node, 0 );
8628     mcIdType* fEnd = revNodal->getPointer() + revNodalIndx->getIJ( node + 1, 0);
8629     auto it = std::find( fBeg, fEnd, face );
8630     if ( it != fEnd )
8631       {
8632         for ( auto it2 = it + 1; it2 < fEnd; ++it2 ) // keep faces sorted
8633           *( it2 - 1 ) = *it2;
8634
8635         *( fEnd - 1 ) = theUndefID;
8636       }
8637   }
8638
8639   //================================================================================
8640   /*!
8641    * \brief Check order of two nodes in a given face
8642    *  \param [inout] n0 - node 1
8643    *  \param [inout] n1 - node 2
8644    *  \param [inout] iFEnc - face
8645    *  \param [inout] mesh - mesh
8646    *  \return bool - true if the nodes are in [ .., n1, n0, ..] order in face
8647    */
8648   //================================================================================
8649
8650   bool isReverseOrder( mcIdType n0,
8651                        mcIdType n1,
8652                        mcIdType iFEnc,
8653                        MEDCouplingUMesh* mesh[] )
8654   {
8655     int iMesh;
8656     mcIdType iF = decodeID( iFEnc, iMesh );
8657
8658     const mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getConstPointer();
8659     const mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getConstPointer();
8660
8661     auto it0 = std::find( conn + connI[ iF ] + 1,
8662                           conn + connI[ iF + 1 ],
8663                           n0 );
8664     auto it1 = std::find( conn + connI[ iF ] + 1,
8665                           conn + connI[ iF + 1 ],
8666                           n1 );
8667     long i0 = it0 - conn;
8668     long i1 = it1 - conn;
8669
8670     bool isRev = ( std::abs( i1 - i0 ) == 1 ) ?  i1 < i0 :  i0 < i1;
8671     return isRev;
8672   }
8673
8674   //================================================================================
8675   /*!
8676    * \brief Change orientation of a face in one of given meshes
8677    *  \param [in] iFEnc - face ID also encoding a mesh index
8678    *  \param [in,out] mesh - object and reference meshes
8679    */
8680   //================================================================================
8681
8682   void reverseFace( mcIdType iFEnc, MEDCouplingUMesh* mesh[] )
8683   {
8684     int iMesh;
8685     mcIdType face = decodeID( iFEnc, iMesh );
8686
8687     mcIdType *conn  = mesh[ iMesh ]->getNodalConnectivity()->getPointer();
8688     mcIdType *connI = mesh[ iMesh ]->getNodalConnectivityIndex()->getPointer();
8689
8690     const INTERP_KERNEL::CellModel& cm =
8691       INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( face ));
8692
8693     cm.changeOrientationOf2D( conn + connI[ face ] + 1,
8694                               (unsigned int)( connI[ face + 1 ] - connI[ face ] - 1 ));
8695     return;
8696   }
8697 }
8698
8699 /// @endcond
8700
8701 //================================================================================
8702 /*!
8703  * \brief Orient cells of \a this 2D mesh equally to \a refFaces
8704  *  \param [in] refFaces - 2D mesh containing correctly oriented faces. It is optional.
8705  *              If there are no cells in \a refFaces or it is nullptr, then any face
8706  *              in \a this mesh is used as a reference
8707  *  \throw If \a this mesh is not well defined.
8708  *  \throw If \a this mesh or \refFaces are not 2D.
8709  *  \throw If \a this mesh and \refFaces do not share nodes.
8710  *  \throw If \a refFaces are not equally oriented.
8711  *  \throw If \a this mesh plus \a refFaces together form a non-manifold mesh.
8712  *
8713  *  \if ENABLE_EXAMPLES
8714  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
8715  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
8716  *  \endif
8717  */
8718 //================================================================================
8719
8720 void MEDCouplingUMesh::orientCorrectly2DCells(const MEDCouplingUMesh* refFaces)
8721 {
8722   checkConsistencyLight();
8723   if ( getMeshDimension() != 2 )
8724     throw INTERP_KERNEL::Exception("The mesh dimension must be 2");
8725   if ( refFaces )
8726     {
8727       refFaces->checkConsistencyLight();
8728       if ( refFaces->getMeshDimension() != 2 )
8729         throw INTERP_KERNEL::Exception("The reference mesh dimension must be 2");
8730       if ( getCoords() != refFaces->getCoords() )
8731         throw INTERP_KERNEL::Exception("Object and reference meshes must share nodes ");
8732       if ( refFaces->getNumberOfCells() == 0 )
8733         refFaces = nullptr;
8734     }
8735   if ( getNumberOfCells() == 0 )
8736     return;
8737
8738   enum { _OBJ, _REF };
8739   MEDCouplingUMesh* mesh[2] = { this, const_cast< MEDCouplingUMesh* >( refFaces ) };
8740   MCAuto<MEDCouplingUMesh> meshPtr;
8741   if ( !mesh[_REF] )
8742     {
8743       meshPtr = mesh[_REF] = MEDCouplingUMesh::New();
8744       mesh[_REF]->setCoords( mesh[_OBJ]->getCoords() );
8745       mesh[_REF]->allocateCells(0);
8746       mesh[_REF]->finishInsertingCells();
8747     }
8748   mcIdType nbFacesToCheck[2] = { mesh[_OBJ]->getNumberOfCells(),
8749                                  mesh[_REF]->getNumberOfCells() };
8750   std::vector< bool > isFaceQueued[ 2 ]; // enqueued faces of 2 meshes
8751   isFaceQueued[_OBJ].resize( nbFacesToCheck[_OBJ] );
8752   isFaceQueued[_REF].resize( nbFacesToCheck[_REF] );
8753
8754   MCAuto<DataArrayIdType> revNodal    [2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8755   MCAuto<DataArrayIdType> revNodalIndx[2] = { DataArrayIdType::New(), DataArrayIdType::New() };
8756   mesh[_OBJ]->getReverseNodalConnectivity( revNodal[_OBJ], revNodalIndx[_OBJ] );
8757   mesh[_REF]->getReverseNodalConnectivity( revNodal[_REF], revNodalIndx[_REF] );
8758
8759   std::vector< mcIdType > faceNodes(4);
8760   std::vector< mcIdType > facesByEdge(4), equalFaces;
8761   std::vector< mcIdType > faceQueue; // starting faces with IDs counted from 1; negative ID mean a face in ref mesh
8762
8763   while ( nbFacesToCheck[_OBJ] + nbFacesToCheck[_REF] > 0 ) // until all faces checked
8764     {
8765       if ( faceQueue.empty() ) // all neighbors checked, find more faces to check
8766         {
8767           for ( int iMesh = 1; iMesh >= 0; --iMesh ) // on [ _REF, _OBJ ]
8768             if ( nbFacesToCheck[iMesh] > 0 )
8769               for ( mcIdType f = 0, nbF = mesh[iMesh]->getNumberOfCells(); f < nbF; ++f )
8770                 if ( !isFaceQueued[iMesh][f] )
8771                   {
8772                     faceQueue.push_back( MEDCouplingImpl::encodeID( f, iMesh ));
8773                     isFaceQueued[ iMesh ][ f ] = true;
8774                     iMesh = 0;
8775                     break;
8776                   }
8777           if ( faceQueue.empty() )
8778             break;
8779         }
8780
8781       mcIdType fID = faceQueue.back();
8782       faceQueue.pop_back();
8783
8784       int iMesh, iMesh2;
8785       mcIdType refFace = MEDCouplingImpl::decodeID( fID, iMesh );
8786
8787       nbFacesToCheck[iMesh]--;
8788
8789       equalFaces.clear();
8790       faceNodes.clear();
8791       mesh[iMesh]->getNodeIdsOfCell( refFace, faceNodes );
8792       const INTERP_KERNEL::CellModel& cm = INTERP_KERNEL::CellModel::GetCellModel( mesh[iMesh]->getTypeOfCell( refFace ));
8793       const int nbEdges = cm.getNumberOfSons();
8794
8795       // loop on edges of the refFace
8796       mcIdType n0 = faceNodes[ nbEdges - 1 ]; // 1st node of edge
8797       for ( int edge = 0; edge < nbEdges; ++edge )
8798         {
8799           mcIdType n1 = faceNodes[ edge ]; // 2nd node of edge
8800
8801           // get faces sharing the edge
8802           MEDCouplingImpl::getFacesOfEdge( n0, n1, fID, mesh, revNodal, revNodalIndx,
8803                                            facesByEdge, equalFaces );
8804
8805           if ( facesByEdge.size() > 1 )
8806             THROW_IK_EXCEPTION("Non-manifold mesh at edge " << n0+1 << " - " << n1+1);
8807
8808           if ( facesByEdge.size() == 1 )
8809             {
8810               // compare orientation of two faces
8811               //
8812               if ( !MEDCouplingImpl::isReverseOrder( n0, n1, facesByEdge[0], mesh ))
8813                 {
8814                   if ( facesByEdge[0] < 0 ) // in the ref mesh
8815                     throw INTERP_KERNEL::Exception("Different orientation of reference faces");
8816
8817                   MEDCouplingImpl::reverseFace( facesByEdge[0], mesh );
8818                 }
8819               mcIdType face2 = MEDCouplingImpl::decodeID( facesByEdge[0], iMesh2 );
8820               if ( !isFaceQueued[iMesh2][face2] )
8821                 {
8822                   isFaceQueued[iMesh2][face2] = true;
8823                   faceQueue.push_back( facesByEdge[0] );
8824                 }
8825             }
8826           n0 = n1;
8827         }
8828
8829       // remove face and equalFaces from revNodal in order not to treat them again
8830       equalFaces.push_back( fID );
8831       for ( mcIdType face : equalFaces )
8832         {
8833           mcIdType f            = MEDCouplingImpl::decodeID( face, iMesh2 );
8834           const mcIdType *conn  = mesh[iMesh2]->getNodalConnectivity()->getConstPointer();
8835           const mcIdType *connI = mesh[iMesh2]->getNodalConnectivityIndex()->getConstPointer();
8836           mcIdType nbNodes      = connI[ f + 1 ] - connI[ f ] - 1;
8837           for ( const mcIdType* n = conn + connI[ f ] + 1, *nEnd = n + nbNodes; n < nEnd; ++n )
8838
8839             MEDCouplingImpl::removeFromRevNodal( *n, f,  // not to treat f again
8840                                                  revNodal[ iMesh2 ], revNodalIndx[ iMesh2 ] );
8841         }
8842
8843     } // while() until all faces checked
8844
8845   return;
8846 }