]> SALOME platform Git repositories - tools/medcoupling.git/blob - src/MEDCoupling/MEDCouplingUMesh.cxx
Salome HOME
ca37145da76b8f489b8ab1505e485296b486e6cc
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (EDF R&D)
20
21 #include "MEDCouplingUMesh.txx"
22 #include "MEDCouplingCMesh.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingFieldDouble.hxx"
25 #include "MEDCouplingSkyLineArray.hxx"
26 #include "CellModel.hxx"
27 #include "VolSurfUser.txx"
28 #include "InterpolationUtils.hxx"
29 #include "PointLocatorAlgos.txx"
30 #include "BBTree.txx"
31 #include "BBTreeDst.txx"
32 #include "SplitterTetra.hxx"
33 #include "DiameterCalculator.hxx"
34 #include "DirectedBoundingBox.hxx"
35 #include "InterpKernelMatrixTools.hxx"
36 #include "InterpKernelMeshQuality.hxx"
37 #include "InterpKernelCellSimplify.hxx"
38 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
39 #include "InterpKernelAutoPtr.hxx"
40 #include "InterpKernelGeo2DNode.hxx"
41 #include "InterpKernelGeo2DEdgeLin.hxx"
42 #include "InterpKernelGeo2DEdgeArcCircle.hxx"
43 #include "InterpKernelGeo2DQuadraticPolygon.hxx"
44 #include "OrientationInverter.hxx"
45 #include "MEDCouplingUMesh_internal.hxx"
46
47 #include <sstream>
48 #include <fstream>
49 #include <numeric>
50 #include <memory>
51 #include <cstring>
52 #include <limits>
53 #include <list>
54
55 using namespace MEDCoupling;
56
57 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
58
59 /// @cond INTERNAL
60
61 const INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::MEDMEM_ORDER[N_MEDMEM_ORDER] = { INTERP_KERNEL::NORM_POINT1, INTERP_KERNEL::NORM_SEG2, INTERP_KERNEL::NORM_SEG3, INTERP_KERNEL::NORM_SEG4, INTERP_KERNEL::NORM_POLYL, INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4, INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_TRI7, INTERP_KERNEL::NORM_QUAD8, INTERP_KERNEL::NORM_QUAD9, INTERP_KERNEL::NORM_POLYGON, INTERP_KERNEL::NORM_QPOLYG, INTERP_KERNEL::NORM_TETRA4, INTERP_KERNEL::NORM_PYRA5, INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXA8, INTERP_KERNEL::NORM_HEXGP12, INTERP_KERNEL::NORM_TETRA10, INTERP_KERNEL::NORM_PYRA13, INTERP_KERNEL::NORM_PENTA15, INTERP_KERNEL::NORM_PENTA18, INTERP_KERNEL::NORM_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
62 /// @endcond
63
64 MEDCouplingUMesh *MEDCouplingUMesh::New()
65 {
66   return new MEDCouplingUMesh;
67 }
68
69 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
70 {
71   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
72   ret->setName(meshName);
73   ret->setMeshDimension(meshDim);
74   return ret;
75 }
76
77 /*!
78  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
79  * between \a this and the new mesh.
80  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
81  *          delete this mesh using decrRef() as it is no more needed.
82  */
83 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
84 {
85   return clone(true);
86 }
87
88
89 /*!
90  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
91  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
92  * this mesh are shared by the new mesh.
93  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
94  *          delete this mesh using decrRef() as it is no more needed.
95  */
96 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
97 {
98   return new MEDCouplingUMesh(*this,recDeepCpy);
99 }
100
101 /*!
102  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
103  * The coordinates are shared between \a this and the returned instance.
104  *
105  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
106  * \sa MEDCouplingUMesh::deepCopy
107  */
108 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
109 {
110   checkConnectivityFullyDefined();
111   MCAuto<MEDCouplingUMesh> ret=clone(false);
112   MCAuto<DataArrayIdType> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
113   ret->setConnectivity(c,ci);
114   return ret.retn();
115 }
116
117 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
118 {
119   if(!other)
120     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
121   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
122   if(!otherC)
123     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
124   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
125   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
126 }
127
128 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
129 {
130   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
131   return ret;
132 }
133
134 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
135 {
136   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
137   ret.push_back(_nodal_connec);
138   ret.push_back(_nodal_connec_index);
139   return ret;
140 }
141
142 void MEDCouplingUMesh::updateTime() const
143 {
144   MEDCouplingPointSet::updateTime();
145   if(_nodal_connec)
146     {
147       updateTimeWith(*_nodal_connec);
148     }
149   if(_nodal_connec_index)
150     {
151       updateTimeWith(*_nodal_connec_index);
152     }
153 }
154
155 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
156 {
157 }
158
159 /*!
160  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
161  * then \a this mesh is most probably is writable, exchangeable and available for most
162  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
163  * this method to check that all is in order with \a this mesh.
164  *  \throw If the mesh dimension is not set.
165  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
166  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
167  *  \throw If the connectivity data array has more than one component.
168  *  \throw If the connectivity data array has a named component.
169  *  \throw If the connectivity index data array has more than one component.
170  *  \throw If the connectivity index data array has a named component.
171  */
172 void MEDCouplingUMesh::checkConsistencyLight() const
173 {
174   if(_mesh_dim<-1)
175     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
176   if(_mesh_dim!=-1)
177     MEDCouplingPointSet::checkConsistencyLight();
178   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
179     {
180       if(ToIdType(INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension())!=_mesh_dim)
181         {
182           std::ostringstream message;
183           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
184           throw INTERP_KERNEL::Exception(message.str().c_str());
185         }
186     }
187   if(_nodal_connec)
188     {
189       if(_nodal_connec->getNumberOfComponents()!=1)
190         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
191       if(_nodal_connec->getInfoOnComponent(0)!="")
192         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
193     }
194   else
195     if(_mesh_dim!=-1)
196       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
197   if(_nodal_connec_index)
198     {
199       if(_nodal_connec_index->getNumberOfComponents()!=1)
200         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
201       if(_nodal_connec_index->getInfoOnComponent(0)!="")
202         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
203     }
204   else
205     if(_mesh_dim!=-1)
206       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
207 }
208
209 /*!
210  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
211  * then \a this mesh is 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.
214  *  \param [in] eps - a not used parameter.
215  *  \throw If the mesh dimension is not set.
216  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
217  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
218  *  \throw If the connectivity data array has more than one component.
219  *  \throw If the connectivity data array has a named component.
220  *  \throw If the connectivity index data array has more than one component.
221  *  \throw If the connectivity index data array has a named component.
222  *  \throw If number of nodes defining an element does not correspond to the type of element.
223  *  \throw If the nodal connectivity includes an invalid node id.
224  */
225 void MEDCouplingUMesh::checkConsistency(double eps) const
226 {
227   checkConsistencyLight();
228   if(_mesh_dim==-1)
229     return ;
230   int meshDim=getMeshDimension();
231   mcIdType nbOfNodes=getNumberOfNodes();
232   mcIdType nbOfCells=getNumberOfCells();
233   const mcIdType *ptr=_nodal_connec->getConstPointer();
234   const mcIdType *ptrI=_nodal_connec_index->getConstPointer();
235   for(mcIdType i=0;i<nbOfCells;i++)
236     {
237       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
238       if(ToIdType(cm.getDimension())!=meshDim)
239         {
240           std::ostringstream oss;
241           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
242           throw INTERP_KERNEL::Exception(oss.str());
243         }
244       mcIdType nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
245       if(!cm.isDynamic())
246         if(nbOfNodesInCell!=ToIdType(cm.getNumberOfNodes()))
247           {
248             std::ostringstream oss;
249             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
250             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
251             throw INTERP_KERNEL::Exception(oss.str());
252           }
253       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
254         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
255           {
256             std::ostringstream oss;
257             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
258             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
259             throw INTERP_KERNEL::Exception(oss.str());
260           }
261       for(const mcIdType *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
262         {
263           mcIdType nodeId=*w;
264           if(nodeId>=0)
265             {
266               if(nodeId>=nbOfNodes)
267                 {
268                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
269                   throw INTERP_KERNEL::Exception(oss.str());
270                 }
271             }
272           else if(nodeId<-1)
273             {
274               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
275               throw INTERP_KERNEL::Exception(oss.str());
276             }
277           else
278             {
279               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
280                 {
281                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
282                   throw INTERP_KERNEL::Exception(oss.str());
283                 }
284             }
285         }
286     }
287 }
288
289 /*!
290  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
291  * elements contained in the mesh. For more info on the mesh dimension see
292  * \ref MEDCouplingUMeshPage.
293  *  \param [in] meshDim - a new mesh dimension.
294  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
295  */
296 void MEDCouplingUMesh::setMeshDimension(int meshDim)
297 {
298   if(meshDim<-1 || meshDim>3)
299     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
300   _mesh_dim=meshDim;
301   declareAsNew();
302 }
303
304 /*!
305  * Allocates memory to store an estimation of the given number of cells.
306  * The closer the estimation to the number of cells effectively inserted, the less need the library requires
307  * to reallocate memory. If the number of cells to be inserted is not known simply assign 0 to this parameter.
308  * If a nodal connectivity previously existed before the call of this method, it will be reset.
309  *
310  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
311  *
312  *  \if ENABLE_EXAMPLES
313  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
314  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
315  *  \endif
316  */
317 void MEDCouplingUMesh::allocateCells(mcIdType nbOfCells)
318 {
319   if(nbOfCells<0)
320     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
321   if(_nodal_connec_index)
322     {
323       _nodal_connec_index->decrRef();
324     }
325   if(_nodal_connec)
326     {
327       _nodal_connec->decrRef();
328     }
329   _nodal_connec_index=DataArrayIdType::New();
330   _nodal_connec_index->reserve(nbOfCells+1);
331   _nodal_connec_index->pushBackSilent(0);
332   _nodal_connec=DataArrayIdType::New();
333   _nodal_connec->reserve(2*nbOfCells);
334   _types.clear();
335   declareAsNew();
336 }
337
338 /*!
339  * Appends a cell to the connectivity array. For deeper understanding what is
340  * happening see \ref MEDCouplingUMeshNodalConnectivity.
341  *  \param [in] type - type of cell to add.
342  *  \param [in] size - number of nodes constituting this cell.
343  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
344  *
345  *  \if ENABLE_EXAMPLES
346  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
347  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
348  *  \endif
349  */
350 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, mcIdType size, const mcIdType *nodalConnOfCell)
351 {
352   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
353   if(_nodal_connec_index==0)
354     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
355   if(ToIdType(cm.getDimension())==_mesh_dim)
356     {
357       if(!cm.isDynamic())
358         if(size!=ToIdType(cm.getNumberOfNodes()))
359           {
360             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
361             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
362             throw INTERP_KERNEL::Exception(oss.str());
363           }
364       mcIdType idx=_nodal_connec_index->back();
365       mcIdType val=idx+size+1;
366       _nodal_connec_index->pushBackSilent(val);
367       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
368       _types.insert(type);
369     }
370   else
371     {
372       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
373       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
374       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
375       throw INTERP_KERNEL::Exception(oss.str());
376     }
377 }
378
379 /*!
380  * Compacts data arrays to release unused memory. This method is to be called after
381  * finishing cell insertion using \a this->insertNextCell().
382  *
383  *  \if ENABLE_EXAMPLES
384  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
385  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
386  *  \endif
387  */
388 void MEDCouplingUMesh::finishInsertingCells()
389 {
390   _nodal_connec->pack();
391   _nodal_connec_index->pack();
392   _nodal_connec->declareAsNew();
393   _nodal_connec_index->declareAsNew();
394   updateTime();
395 }
396
397 /*!
398  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
399  * Useful for python users.
400  */
401 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
402 {
403   return new MEDCouplingUMeshCellIterator(this);
404 }
405
406 /*!
407  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
408  * If \a this is not so that the cells are grouped by geo types, this method will throw an exception.
409  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
410  * Useful for python users.
411  */
412 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
413 {
414   if(!checkConsecutiveCellTypes())
415     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
416   return new MEDCouplingUMeshCellByTypeEntry(this);
417 }
418
419 /*!
420  * Returns a set of all cell types available in \a this mesh.
421  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
422  * \warning this method does not throw any exception even if \a this is not defined.
423  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
424  */
425 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
426 {
427   return _types;
428 }
429
430 /*!
431  * This method returns the sorted list of geometric types in \a this.
432  * 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
433  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
434  *
435  * \throw if connectivity in \a this is not correctly defined.
436  *
437  * \sa MEDCouplingMesh::getAllGeoTypes
438  */
439 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
440 {
441   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
442   checkConnectivityFullyDefined();
443   mcIdType nbOfCells=getNumberOfCells();
444   if(nbOfCells==0)
445     return ret;
446   if(getNodalConnectivityArrayLen()<1)
447     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
448   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
449   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
450   for(mcIdType i=1;i<nbOfCells;i++,ci++)
451     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
452       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
453   return ret;
454 }
455
456 /*!
457  * This method is a method that compares \a this and \a other.
458  * This method compares \b all attributes, even names and component names.
459  */
460 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
461 {
462   if(!other)
463     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
464   std::ostringstream oss; oss.precision(15);
465   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
466   if(!otherC)
467     {
468       reason="mesh given in input is not castable in MEDCouplingUMesh !";
469       return false;
470     }
471   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
472     return false;
473   if(_mesh_dim!=otherC->_mesh_dim)
474     {
475       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
476       reason=oss.str();
477       return false;
478     }
479   if(_types!=otherC->_types)
480     {
481       oss << "umesh geometric type mismatch :\nThis geometric types are :";
482       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
483         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
484       oss << "\nOther geometric types are :";
485       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
486         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
487       reason=oss.str();
488       return false;
489     }
490   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
491     if(_nodal_connec==0 || otherC->_nodal_connec==0)
492       {
493         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
494         return false;
495       }
496   if(_nodal_connec!=otherC->_nodal_connec)
497     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
498       {
499         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
500         return false;
501       }
502   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
503     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
504       {
505         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
506         return false;
507       }
508   if(_nodal_connec_index!=otherC->_nodal_connec_index)
509     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
510       {
511         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
512         return false;
513       }
514   return true;
515 }
516
517 /*!
518  * Checks if data arrays of this mesh (node coordinates, nodal
519  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
520  * not considered.
521  *  \param [in] other - the mesh to compare with.
522  *  \param [in] prec - precision value used to compare node coordinates.
523  *  \return bool - \a true if the two meshes are same.
524  */
525 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
526 {
527   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
528   if(!otherC)
529     return false;
530   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
531     return false;
532   if(_mesh_dim!=otherC->_mesh_dim)
533     return false;
534   if(_types!=otherC->_types)
535     return false;
536   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
537     if(_nodal_connec==0 || otherC->_nodal_connec==0)
538       return false;
539   if(_nodal_connec!=otherC->_nodal_connec)
540     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
541       return false;
542   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
543     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
544       return false;
545   if(_nodal_connec_index!=otherC->_nodal_connec_index)
546     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
547       return false;
548   return true;
549 }
550
551 /*!
552  * Checks if \a this and \a other meshes are geometrically equivalent with high
553  * probability, else an exception is thrown. The meshes are considered equivalent if
554  * (1) meshes contain the same number of nodes and the same number of elements of the
555  * same types (2) three cells of the two meshes (first, last and middle) are based
556  * on coincident nodes (with a specified precision).
557  *  \param [in] other - the mesh to compare with.
558  *  \param [in] prec - the precision used to compare nodes of the two meshes.
559  *  \throw If the two meshes do not match.
560  */
561 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
562 {
563   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
564   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
565   if(!otherC)
566     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !");
567 }
568
569 /*!
570  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
571  * cells each node belongs to.
572  * \warning For speed reasons, this method does not check if node ids in the nodal
573  *          connectivity correspond to the size of node coordinates array.
574  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
575  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
576  *        dividing cell ids in \a revNodal into groups each referring to one
577  *        node. Its every element (except the last one) is an index pointing to the
578  *         first id of a group of cells. For example cells sharing the node #1 are
579  *        described by following range of indices:
580  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
581  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
582  *        Number of cells sharing the *i*-th node is
583  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
584  * \throw If the coordinates array is not set.
585  * \throw If the nodal connectivity of cells is not defined.
586  *
587  * \if ENABLE_EXAMPLES
588  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
589  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
590  * \endif
591  */
592 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayIdType *revNodal, DataArrayIdType *revNodalIndx) const
593 {
594   checkFullyDefined();
595   mcIdType nbOfNodes(getNumberOfNodes());
596   mcIdType *revNodalIndxPtr=(mcIdType *)malloc((nbOfNodes+1)*sizeof(mcIdType));
597   revNodalIndx->useArray(revNodalIndxPtr,true,DeallocType::C_DEALLOC,nbOfNodes+1,1);
598   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
599   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
600   mcIdType nbOfCells(getNumberOfCells()),nbOfEltsInRevNodal(0);
601   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
602     {
603       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
604       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
605         if(*iter>=0)//for polyhedrons
606           {
607             nbOfEltsInRevNodal++;
608             revNodalIndxPtr[(*iter)+1]++;
609           }
610     }
611   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<mcIdType>());
612   mcIdType *revNodalPtr=(mcIdType *)malloc(nbOfEltsInRevNodal*sizeof(mcIdType));
613   revNodal->useArray(revNodalPtr,true,DeallocType::C_DEALLOC,nbOfEltsInRevNodal,1);
614   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
615   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
616     {
617       const mcIdType *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
618       const mcIdType *endNdlConnOfCurCell=conn+connIndex[eltId+1];
619       for(const mcIdType *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
620         if(*iter>=0)//for polyhedrons
621           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<mcIdType>(),-1))=eltId;
622     }
623 }
624
625 /*!
626  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
627  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
628  * describing correspondence between cells of \a this and the result meshes are
629  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
630  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
631  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
632  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
633  * \warning For speed reasons, this method does not check if node ids in the nodal
634  *          connectivity correspond to the size of node coordinates array.
635  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
636  *          to write this mesh to the MED file, its cells must be sorted using
637  *          sortCellsInMEDFileFrmt().
638  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
639  *         each cell of \a this mesh.
640  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
641  *        dividing cell ids in \a desc into groups each referring to one
642  *        cell of \a this mesh. Its every element (except the last one) is an index
643  *        pointing to the first id of a group of cells. For example cells of the
644  *        result mesh bounding the cell #1 of \a this mesh are described by following
645  *        range of indices:
646  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
647  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
648  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
649  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
650  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
651  *         by each cell of the result mesh.
652  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
653  *        in the result mesh,
654  *        dividing cell ids in \a revDesc into groups each referring to one
655  *        cell of the result mesh the same way as \a descIndx divides \a desc.
656  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
657  *        delete this mesh using decrRef() as it is no more needed.
658  *  \throw If the coordinates array is not set.
659  *  \throw If the nodal connectivity of cells is node defined.
660  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
661  *         revDescIndx == NULL.
662  *
663  *  \if ENABLE_EXAMPLES
664  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
665  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
666  *  \endif
667  * \sa buildDescendingConnectivity2()
668  */
669 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
670 {
671   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
672 }
673
674 /*!
675  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
676  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
677  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
678  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
679  * \sa MEDCouplingUMesh::buildDescendingConnectivity
680  */
681 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
682 {
683   checkFullyDefined();
684   if(getMeshDimension()!=3)
685     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
686   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
687 }
688
689 /*!
690  * 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.
691  * This method works for both meshes with mesh dimension equal to 2 or 3. Dynamical cells are not supported (polygons, polyhedrons...)
692  * 
693  * \sa explode3DMeshTo1D, buildDescendingConnectiviy
694  */
695 MEDCouplingUMesh *MEDCouplingUMesh::explodeMeshIntoMicroEdges(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
696 {
697    checkFullyDefined();
698    switch(getMeshDimension())
699      {
700      case 2:
701        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
702      case 3:
703        return buildDescendingConnectivityGen<MicroEdgesGenerator2D>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
704      default:
705        throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explodeMeshIntoMicroEdges : Only 2D and 3D supported !");
706      }
707 }
708
709 /*!
710  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
711  * this->getMeshDimension(), that bound cells of \a this mesh. In
712  * addition arrays describing correspondence between cells of \a this and the result
713  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
714  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
715  *  mesh. This method differs from buildDescendingConnectivity() in that apart
716  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
717  * result meshes. So a positive id means that order of nodes in corresponding cells
718  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
719  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
720  * i.e. cell ids are one-based.
721  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
722  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh.
723  * \warning For speed reasons, this method does not check if node ids in the nodal
724  *          connectivity correspond to the size of node coordinates array.
725  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
726  *          to write this mesh to the MED file, its cells must be sorted using
727  *          sortCellsInMEDFileFrmt().
728  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
729  *         each cell of \a this mesh.
730  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
731  *        dividing cell ids in \a desc into groups each referring to one
732  *        cell of \a this mesh. Its every element (except the last one) is an index
733  *        pointing to the first id of a group of cells. For example cells of the
734  *        result mesh bounding the cell #1 of \a this mesh are described by following
735  *        range of indices:
736  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
737  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
738  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
739  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
740  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
741  *         by each cell of the result mesh.
742  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
743  *        in the result mesh,
744  *        dividing cell ids in \a revDesc into groups each referring to one
745  *        cell of the result mesh the same way as \a descIndx divides \a desc.
746  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
747  *        shares the node coordinates array with \a this mesh. The caller is to
748  *        delete this mesh using decrRef() as it is no more needed.
749  *  \throw If the coordinates array is not set.
750  *  \throw If the nodal connectivity of cells is node defined.
751  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
752  *         revDescIndx == NULL.
753  *
754  *  \if ENABLE_EXAMPLES
755  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
756  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
757  *  \endif
758  * \sa buildDescendingConnectivity()
759  */
760 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *revDesc, DataArrayIdType *revDescIndx) const
761 {
762   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
763 }
764
765 /*!
766  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
767  * For speed reasons no check of this will be done. This method calls
768  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
769  * This method lists cell by cell in \b this which are its neighbors. To compute the result
770  * only connectivities are considered.
771  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
772  * The format of return is hence \ref numbering-indirect.
773  *
774  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
775  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
776  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
777  * is equal to the last values in \b neighborsIndx.
778  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
779  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
780  */
781 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx) const
782 {
783   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
784   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
785   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
786   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
787   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
788   meshDM1=0;
789   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
790 }
791
792 void MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne(const DataArrayIdType *nodeNeigh, const DataArrayIdType *nodeNeighI, MCAuto<DataArrayIdType>& cellNeigh, MCAuto<DataArrayIdType>& cellNeighIndex) const
793 {
794   if(!nodeNeigh || !nodeNeighI)
795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : null pointer !");
796   checkConsistencyLight();
797   nodeNeigh->checkAllocated(); nodeNeighI->checkAllocated();
798   nodeNeigh->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh");
799   nodeNeighI->checkNbOfComps(1,"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : node neigh index");
800   nodeNeighI->checkNbOfTuples(1+getNumberOfNodes(),"MEDCouplingUMesh::computeCellNeighborhoodFromNodesOne : invalid length");
801   mcIdType nbCells=getNumberOfCells();
802   const mcIdType *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin()),*ne(nodeNeigh->begin()),*nei(nodeNeighI->begin());
803   cellNeigh=DataArrayIdType::New(); cellNeigh->alloc(0,1); cellNeighIndex=DataArrayIdType::New(); cellNeighIndex->alloc(1,1); cellNeighIndex->setIJ(0,0,0);
804   for(mcIdType i=0;i<nbCells;i++)
805     {
806       std::set<mcIdType> s;
807       for(const mcIdType *it=c+ci[i]+1;it!=c+ci[i+1];it++)
808         if(*it>=0)
809           s.insert(ne+nei[*it],ne+nei[*it+1]);
810       s.erase(i);
811       cellNeigh->insertAtTheEnd(s.begin(),s.end());
812       cellNeighIndex->pushBackSilent(cellNeigh->getNumberOfTuples());
813     }
814 }
815
816 /*!
817  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
818  * of MEDCouplingUMesh::computeNeighborsOfCells.
819  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
820  * typically the case to extract a set a neighbours,
821  * excluding a set of meshdim-1 cells in input descending connectivity.
822  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
823  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
824  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
825  * are considered.
826  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
827  *
828  * \param [in] desc descending connectivity array.
829  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
830  * \param [in] revDesc reverse descending connectivity array.
831  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
832  * \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
833  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
834  * \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.
835  */
836 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayIdType *desc, const DataArrayIdType *descIndx, const DataArrayIdType *revDesc, const DataArrayIdType *revDescIndx,
837                                                   DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIndx)
838 {
839   if(!desc || !descIndx || !revDesc || !revDescIndx)
840     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
841   const mcIdType *descPtr=desc->begin();
842   const mcIdType *descIPtr=descIndx->begin();
843   const mcIdType *revDescPtr=revDesc->begin();
844   const mcIdType *revDescIPtr=revDescIndx->begin();
845   //
846   mcIdType nbCells=descIndx->getNumberOfTuples()-1;
847   MCAuto<DataArrayIdType> out0=DataArrayIdType::New();
848   MCAuto<DataArrayIdType> out1=DataArrayIdType::New(); out1->alloc(nbCells+1,1);
849   mcIdType *out1Ptr=out1->getPointer();
850   *out1Ptr++=0;
851   out0->reserve(desc->getNumberOfTuples());
852   for(mcIdType i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
853     {
854       for(const mcIdType *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
855         {
856           std::set<mcIdType> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
857           s.erase(i);
858           out0->insertAtTheEnd(s.begin(),s.end());
859         }
860       *out1Ptr=out0->getNumberOfTuples();
861     }
862   neighbors=out0.retn();
863   neighborsIndx=out1.retn();
864 }
865
866 /*!
867  * Explodes \a this into edges whatever its dimension.
868  */
869 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::explodeIntoEdges(MCAuto<DataArrayIdType>& desc, MCAuto<DataArrayIdType>& descIndex, MCAuto<DataArrayIdType>& revDesc, MCAuto<DataArrayIdType>& revDescIndx) const
870 {
871   checkFullyDefined();
872   int mdim(getMeshDimension());
873   desc=DataArrayIdType::New(); descIndex=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
874   MCAuto<MEDCouplingUMesh> mesh1D;
875   switch(mdim)
876   {
877     case 3:
878       {
879         mesh1D=explode3DMeshTo1D(desc,descIndex,revDesc,revDescIndx);
880         break;
881       }
882     case 2:
883       {
884         mesh1D=buildDescendingConnectivity(desc,descIndex,revDesc,revDescIndx);
885         break;
886       }
887     default:
888       {
889         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2] !");
890       }
891   }
892   return mesh1D;
893 }
894
895 /*!
896  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
897  * For speed reasons no check of this will be done. This method calls
898  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
899  * This method lists node by node in \b this which are its neighbors. To compute the result
900  * only connectivities are considered.
901  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
902  *
903  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
904  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
905  * parameter allows to select the right part in this array (\ref numbering-indirect).
906  * The number of tuples is equal to the last values in \b neighborsIndx.
907  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
908  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
909  *
910  * \sa MEDCouplingUMesh::computeEnlargedNeighborsOfNodes
911  */
912 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayIdType *&neighbors, DataArrayIdType *&neighborsIdx) const
913 {
914   checkFullyDefined();
915   mcIdType mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
916   MCAuto<DataArrayIdType> desc(DataArrayIdType::New()),descIndx(DataArrayIdType::New()),revDesc(DataArrayIdType::New()),revDescIndx(DataArrayIdType::New());
917   MCConstAuto<MEDCouplingUMesh> mesh1D;
918   switch(mdim)
919   {
920     case 3:
921       {
922         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
923         break;
924       }
925     case 2:
926       {
927         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
928         break;
929       }
930     case 1:
931       {
932         mesh1D.takeRef(this);
933         break;
934       }
935     default:
936       {
937         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
938       }
939   }
940   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=0; revDescIndx=0;
941   mesh1D->getReverseNodalConnectivity(desc,descIndx);
942   MCAuto<DataArrayIdType> ret0(DataArrayIdType::New());
943   ret0->alloc(desc->getNumberOfTuples(),1);
944   mcIdType *r0Pt(ret0->getPointer());
945   const mcIdType *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
946   for(mcIdType i=0;i<nbNodes;i++,rni++)
947     {
948       for(const mcIdType *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
949         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
950     }
951   neighbors=ret0.retn();
952   neighborsIdx=descIndx.retn();
953 }
954
955 /*!
956  * 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.
957  * 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.
958  * This method is useful to find ghost cells of a part of a mesh with a code based on fields on nodes.
959  *
960  * \sa MEDCouplingUMesh::computeNeighborsOfNodes
961  */
962 void MEDCouplingUMesh::computeEnlargedNeighborsOfNodes(MCAuto<DataArrayIdType> &neighbors, MCAuto<DataArrayIdType>& neighborsIdx) const
963 {
964   checkFullyDefined();
965   mcIdType nbOfNodes(getNumberOfNodes());
966   const mcIdType *conn(_nodal_connec->begin()),*connIndex(_nodal_connec_index->begin());
967   mcIdType nbOfCells=getNumberOfCells();
968   std::vector< std::set<mcIdType> > st0(nbOfNodes);
969   for(mcIdType eltId=0;eltId<nbOfCells;eltId++)
970     {
971       const mcIdType *strtNdlConnOfCurCell(conn+connIndex[eltId]+1),*endNdlConnOfCurCell(conn+connIndex[eltId+1]);
972       std::set<mcIdType> s(strtNdlConnOfCurCell,endNdlConnOfCurCell); s.erase(-1); //for polyhedrons
973       for(std::set<mcIdType>::const_iterator iter2=s.begin();iter2!=s.end();iter2++)
974         st0[*iter2].insert(s.begin(),s.end());
975     }
976   neighborsIdx=DataArrayIdType::New(); neighborsIdx->alloc(nbOfNodes+1,1); neighborsIdx->setIJ(0,0,0);
977   {
978     mcIdType *neighIdx(neighborsIdx->getPointer());
979     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++)
980       {
981         if ((*it).empty())
982           neighIdx[1]=neighIdx[0];
983         else
984           neighIdx[1]=neighIdx[0]+ToIdType((*it).size())-1;
985       }
986   }
987   neighbors=DataArrayIdType::New(); neighbors->alloc(neighborsIdx->back(),1);
988   {
989     const mcIdType *neighIdx(neighborsIdx->begin());
990     mcIdType *neigh(neighbors->getPointer()),nodeId(0);
991     for(std::vector< std::set<mcIdType> >::const_iterator it=st0.begin();it!=st0.end();it++,neighIdx++,nodeId++)
992       {
993         std::set<mcIdType> s(*it); s.erase(nodeId);
994         std::copy(s.begin(),s.end(),neigh+*neighIdx);
995       }
996   }
997 }
998
999 /*!
1000  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1001  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1002  * array of cell ids. Pay attention that after conversion all algorithms work slower
1003  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1004  * conversion due presence of invalid ids in the array of cells to convert, as a
1005  * result \a this mesh contains some already converted elements. In this case the 2D
1006  * mesh remains valid but 3D mesh becomes \b inconsistent!
1007  *  \warning This method can significantly modify the order of geometric types in \a this,
1008  *          hence, to write this mesh to the MED file, its cells must be sorted using
1009  *          sortCellsInMEDFileFrmt().
1010  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1011  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1012  *         cellIdsToConvertBg.
1013  *  \throw If the coordinates array is not set.
1014  *  \throw If the nodal connectivity of cells is node defined.
1015  *  \throw If dimension of \a this mesh is not either 2 or 3.
1016  *
1017  *  \if ENABLE_EXAMPLES
1018  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1019  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1020  *  \endif
1021  */
1022 void MEDCouplingUMesh::convertToPolyTypes(const mcIdType *cellIdsToConvertBg, const mcIdType *cellIdsToConvertEnd)
1023 {
1024   checkFullyDefined();
1025   int dim=getMeshDimension();
1026   if(dim<2 || dim>3)
1027     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1028   mcIdType nbOfCells=getNumberOfCells();
1029   if(dim==2)
1030     {
1031       const mcIdType *connIndex=_nodal_connec_index->begin();
1032       mcIdType *conn=_nodal_connec->getPointer();
1033       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1034         {
1035           if(*iter>=0 && *iter<nbOfCells)
1036             {
1037               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1038               if(!cm.isQuadratic())
1039                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1040               else
1041                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1042             }
1043           else
1044             {
1045               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1046               oss << " in range [0," << nbOfCells << ") !";
1047               throw INTERP_KERNEL::Exception(oss.str());
1048             }
1049         }
1050     }
1051   else
1052     {
1053       mcIdType *connIndex(_nodal_connec_index->getPointer());
1054       const mcIdType *connOld(_nodal_connec->getConstPointer());
1055       MCAuto<DataArrayIdType> connNew(DataArrayIdType::New()),connNewI(DataArrayIdType::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1056       std::vector<bool> toBeDone(nbOfCells,false);
1057       for(const mcIdType *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1058         {
1059           if(*iter>=0 && *iter<nbOfCells)
1060             toBeDone[*iter]=true;
1061           else
1062             {
1063               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1064               oss << " in range [0," << nbOfCells << ") !";
1065               throw INTERP_KERNEL::Exception(oss.str());
1066             }
1067         }
1068       for(mcIdType cellId=0;cellId<nbOfCells;cellId++)
1069         {
1070           mcIdType pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1071           mcIdType lgthOld(posP1-pos-1);
1072           if(toBeDone[cellId])
1073             {
1074               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1075               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1076               mcIdType *tmp(new mcIdType[nbOfFaces*lgthOld+1]);
1077               mcIdType *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1078               for(unsigned j=0;j<nbOfFaces;j++)
1079                 {
1080                   INTERP_KERNEL::NormalizedCellType type;
1081                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1082                   work+=offset;
1083                   *work++=-1;
1084                 }
1085               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1086               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1087               connNewI->pushBackSilent(connNewI->back()+ToIdType(newLgth));
1088               delete [] tmp;
1089             }
1090           else
1091             {
1092               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1093               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1094             }
1095         }
1096       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1097     }
1098   computeTypes();
1099 }
1100
1101 /*!
1102  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1103  * polyhedrons (if \a this is a 3D mesh).
1104  *  \warning As this method is purely for user-friendliness and no optimization is
1105  *          done to avoid construction of a useless vector, this method can be costly
1106  *          in memory.
1107  *  \throw If the coordinates array is not set.
1108  *  \throw If the nodal connectivity of cells is node defined.
1109  *  \throw If dimension of \a this mesh is not either 2 or 3.
1110  */
1111 void MEDCouplingUMesh::convertAllToPoly()
1112 {
1113   mcIdType nbOfCells=getNumberOfCells();
1114   std::vector<mcIdType> cellIds(nbOfCells);
1115   for(mcIdType i=0;i<nbOfCells;i++)
1116     cellIds[i]=i;
1117   convertToPolyTypes(&cellIds[0],&cellIds[0]+ToIdType(cellIds.size()));
1118 }
1119
1120 /*!
1121  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1122  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1123  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1124  * base facet of the volume and the second half of nodes describes an opposite facet
1125  * having the same number of nodes as the base one. This method converts such
1126  * connectivity to a valid polyhedral format where connectivity of each facet is
1127  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1128  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1129  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1130  * a correct orientation of the first facet of a polyhedron, else orientation of a
1131  * corrected cell is reverse.<br>
1132  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1133  * it releases the user from boring description of polyhedra connectivity in the valid
1134  * format.
1135  *  \throw If \a this->getMeshDimension() != 3.
1136  *  \throw If \a this->getSpaceDimension() != 3.
1137  *  \throw If the nodal connectivity of cells is not defined.
1138  *  \throw If the coordinates array is not set.
1139  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1140  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1141  *
1142  *  \if ENABLE_EXAMPLES
1143  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1144  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1145  *  \endif
1146  */
1147 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1148 {
1149   checkFullyDefined();
1150   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1151     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1152   mcIdType nbOfCells=getNumberOfCells();
1153   MCAuto<DataArrayIdType> newCi=DataArrayIdType::New();
1154   newCi->alloc(nbOfCells+1,1);
1155   mcIdType *newci=newCi->getPointer();
1156   const mcIdType *ci=_nodal_connec_index->getConstPointer();
1157   const mcIdType *c=_nodal_connec->getConstPointer();
1158   newci[0]=0;
1159   for(mcIdType i=0;i<nbOfCells;i++)
1160     {
1161       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1162       if(type==INTERP_KERNEL::NORM_POLYHED)
1163         {
1164           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1165             {
1166               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1167               throw INTERP_KERNEL::Exception(oss.str());
1168             }
1169           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1170           if(n2%2!=0)
1171             {
1172               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 !";
1173               throw INTERP_KERNEL::Exception(oss.str());
1174             }
1175           mcIdType n1=ToIdType(n2/2);
1176           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)
1177         }
1178       else
1179         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1180     }
1181   MCAuto<DataArrayIdType> newC=DataArrayIdType::New();
1182   newC->alloc(newci[nbOfCells],1);
1183   mcIdType *newc=newC->getPointer();
1184   for(mcIdType i=0;i<nbOfCells;i++)
1185     {
1186       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1187       if(type==INTERP_KERNEL::NORM_POLYHED)
1188         {
1189           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1190           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1191           *newc++=-1;
1192           for(std::size_t j=0;j<n1;j++)
1193             {
1194               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1195               newc[n1+5*j]=-1;
1196               newc[n1+5*j+1]=c[ci[i]+1+j];
1197               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1198               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1199               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1200             }
1201           newc+=n1*6;
1202         }
1203       else
1204         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1205     }
1206   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1207   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1208 }
1209
1210
1211 /*!
1212  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1213  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1214  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1215  *          to write this mesh to the MED file, its cells must be sorted using
1216  *          sortCellsInMEDFileFrmt().
1217  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1218  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1219  * \return \c true if at least one cell has been converted, \c false else. In the
1220  *         last case the nodal connectivity remains unchanged.
1221  * \throw If the coordinates array is not set.
1222  * \throw If the nodal connectivity of cells is not defined.
1223  * \throw If \a this->getMeshDimension() < 0.
1224  */
1225 bool MEDCouplingUMesh::unPolyze()
1226 {
1227   checkFullyDefined();
1228   int mdim=getMeshDimension();
1229   if(mdim<0)
1230     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1231   if(mdim<=1)
1232     return false;
1233   mcIdType nbOfCells=getNumberOfCells();
1234   if(nbOfCells<1)
1235     return false;
1236   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
1237   mcIdType *conn=_nodal_connec->getPointer();
1238   mcIdType *index=_nodal_connec_index->getPointer();
1239   mcIdType posOfCurCell=0;
1240   mcIdType newPos=0;
1241   mcIdType lgthOfCurCell;
1242   bool ret=false;
1243   for(mcIdType i=0;i<nbOfCells;i++)
1244     {
1245       lgthOfCurCell=index[i+1]-posOfCurCell;
1246       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1247       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1248       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1249       mcIdType newLgth;
1250       if(cm.isDynamic())
1251         {
1252           switch(cm.getDimension())
1253           {
1254             case 2:
1255               {
1256                 INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[lgthOfCurCell-1];
1257                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(mcIdType *)tmp);
1258                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1259                 break;
1260               }
1261             case 3:
1262               {
1263                 mcIdType nbOfFaces,lgthOfPolyhConn;
1264                 INTERP_KERNEL::AutoPtr<mcIdType> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1265                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1266                 break;
1267               }
1268             case 1:
1269               {
1270                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1271                 break;
1272               }
1273           }
1274           ret=ret || (newType!=type);
1275           conn[newPos]=newType;
1276           newPos+=newLgth+1;
1277           posOfCurCell=index[i+1];
1278           index[i+1]=newPos;
1279         }
1280       else
1281         {
1282           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1283           newPos+=lgthOfCurCell;
1284           posOfCurCell+=lgthOfCurCell;
1285           index[i+1]=newPos;
1286         }
1287     }
1288   if(newPos!=initMeshLgth)
1289     _nodal_connec->reAlloc(newPos);
1290   if(ret)
1291     computeTypes();
1292   return ret;
1293 }
1294
1295 /*!
1296  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1297  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1298  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells.
1299  *
1300  * \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
1301  *             precision.
1302  */
1303 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1304 {
1305   checkFullyDefined();
1306   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1307     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1308   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1309   coords->recenterForMaxPrecision(eps);
1310   //
1311   mcIdType nbOfCells=getNumberOfCells();
1312   const mcIdType *conn=_nodal_connec->getConstPointer();
1313   const mcIdType *index=_nodal_connec_index->getConstPointer();
1314   MCAuto<DataArrayIdType> connINew=DataArrayIdType::New();
1315   connINew->alloc(nbOfCells+1,1);
1316   mcIdType *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1317   MCAuto<DataArrayIdType> connNew=DataArrayIdType::New(); connNew->alloc(0,1);
1318   MCAuto<DataArrayIdType> E_Fi(DataArrayIdType::New()), E_F(DataArrayIdType::New()), F_Ei(DataArrayIdType::New()), F_E(DataArrayIdType::New());
1319   MCAuto<MEDCouplingUMesh> m_faces(buildDescendingConnectivity(E_F, E_Fi, F_E, F_Ei));
1320   bool changed=false;
1321   for(mcIdType i=0;i<nbOfCells;i++,connINewPtr++)
1322     {
1323       if(conn[index[i]]==ToIdType(INTERP_KERNEL::NORM_POLYHED))
1324         {
1325           SimplifyPolyhedronCell(eps,coords, i,connNew, m_faces, E_Fi, E_F, F_Ei, F_E);
1326           changed=true;
1327         }
1328       else
1329         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1330       *connINewPtr=connNew->getNumberOfTuples();
1331     }
1332   if(changed)
1333     setConnectivity(connNew,connINew,false);
1334 }
1335
1336 /*!
1337  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1338  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1339  * the format of the returned DataArrayIdType instance.
1340  *
1341  * \return a newly allocated DataArrayIdType sorted ascendingly of fetched node ids.
1342  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1343  */
1344 DataArrayIdType *MEDCouplingUMesh::computeFetchedNodeIds() const
1345 {
1346   checkConnectivityFullyDefined();
1347   const mcIdType *maxEltPt(std::max_element(_nodal_connec->begin(),_nodal_connec->end()));
1348   mcIdType maxElt(maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1);
1349   std::vector<bool> retS(maxElt,false);
1350   computeNodeIdsAlg(retS);
1351   return DataArrayIdType::BuildListOfSwitchedOn(retS);
1352 }
1353
1354 /*!
1355  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1356  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1357  */
1358 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1359 {
1360   mcIdType nbOfNodes=ToIdType(nodeIdsInUse.size()),
1361            nbOfCells=getNumberOfCells();
1362   const mcIdType *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1363   for(mcIdType i=0;i<nbOfCells;i++)
1364     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1365       if(conn[j]>=0)
1366         {
1367           if(conn[j]<nbOfNodes)
1368             nodeIdsInUse[conn[j]]=true;
1369           else
1370             {
1371               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1372               throw INTERP_KERNEL::Exception(oss.str());
1373             }
1374         }
1375 }
1376
1377 /// @cond INTERNAL
1378
1379 struct MEDCouplingAccVisit
1380 {
1381   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1382   mcIdType operator()(mcIdType val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1383   mcIdType _new_nb_of_nodes;
1384 };
1385
1386 /// @endcond
1387
1388 /*!
1389  * Finds nodes not used in any cell and returns an array giving a new id to every node
1390  * by excluding the unused nodes, for which the array holds -1. The result array is
1391  * a mapping in "Old to New" mode.
1392  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1393  *  \return DataArrayIdType * - a new instance of DataArrayIdType. Its length is \a
1394  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1395  *          if the node is unused or a new id else. The caller is to delete this
1396  *          array using decrRef() as it is no more needed.
1397  *  \throw If the coordinates array is not set.
1398  *  \throw If the nodal connectivity of cells is not defined.
1399  *  \throw If the nodal connectivity includes an invalid id.
1400  *
1401  *  \if ENABLE_EXAMPLES
1402  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1403  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1404  *  \endif
1405  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1406  */
1407 DataArrayIdType *MEDCouplingUMesh::getNodeIdsInUse(mcIdType& nbrOfNodesInUse) const
1408 {
1409   nbrOfNodesInUse=-1;
1410   mcIdType nbOfNodes(getNumberOfNodes());
1411   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1412   ret->alloc(nbOfNodes,1);
1413   mcIdType *traducer=ret->getPointer();
1414   std::fill(traducer,traducer+nbOfNodes,-1);
1415   mcIdType nbOfCells=getNumberOfCells();
1416   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
1417   const mcIdType *conn=_nodal_connec->getConstPointer();
1418   for(mcIdType i=0;i<nbOfCells;i++)
1419     for(mcIdType j=connIndex[i]+1;j<connIndex[i+1];j++)
1420       if(conn[j]>=0)
1421         {
1422           if(conn[j]<nbOfNodes)
1423             traducer[conn[j]]=1;
1424           else
1425             {
1426               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1427               throw INTERP_KERNEL::Exception(oss.str());
1428             }
1429         }
1430   nbrOfNodesInUse=ToIdType(std::count(traducer,traducer+nbOfNodes,1));
1431   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1432   return ret.retn();
1433 }
1434
1435 /*!
1436  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1437  * For each cell in \b this the number of nodes constituting cell is computed.
1438  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1439  * So for pohyhedrons some nodes can be counted several times in the returned result.
1440  *
1441  * \return a newly allocated array
1442  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1443  */
1444 DataArrayIdType *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1445 {
1446   checkConnectivityFullyDefined();
1447   mcIdType nbOfCells=getNumberOfCells();
1448   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1449   ret->alloc(nbOfCells,1);
1450   mcIdType *retPtr=ret->getPointer();
1451   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1452   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1453   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1454     {
1455       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1456         *retPtr=connI[i+1]-connI[i]-1;
1457       else
1458         *retPtr=connI[i+1]-connI[i]-1-ToIdType(std::count(conn+connI[i]+1,conn+connI[i+1],-1));
1459     }
1460   return ret.retn();
1461 }
1462
1463 /*!
1464  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1465  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1466  *
1467  * \return DataArrayIdType * - new object to be deallocated by the caller.
1468  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1469  */
1470 DataArrayIdType *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1471 {
1472   checkConnectivityFullyDefined();
1473   mcIdType nbOfCells=getNumberOfCells();
1474   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1475   ret->alloc(nbOfCells,1);
1476   mcIdType *retPtr=ret->getPointer();
1477   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1478   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1479   for(mcIdType i=0;i<nbOfCells;i++,retPtr++)
1480     {
1481       std::set<mcIdType> s(conn+connI[i]+1,conn+connI[i+1]);
1482       if(conn[connI[i]]!=ToIdType(INTERP_KERNEL::NORM_POLYHED))
1483         *retPtr=ToIdType(s.size());
1484       else
1485         {
1486           s.erase(-1);
1487           *retPtr=ToIdType(s.size());
1488         }
1489     }
1490   return ret.retn();
1491 }
1492
1493 /*!
1494  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1495  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1496  *
1497  * \return a newly allocated array
1498  */
1499 DataArrayIdType *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1500 {
1501   checkConnectivityFullyDefined();
1502   mcIdType nbOfCells=getNumberOfCells();
1503   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
1504   ret->alloc(nbOfCells,1);
1505   mcIdType *retPtr=ret->getPointer();
1506   const mcIdType *conn=getNodalConnectivity()->getConstPointer();
1507   const mcIdType *connI=getNodalConnectivityIndex()->getConstPointer();
1508   for(mcIdType i=0;i<nbOfCells;i++,retPtr++,connI++)
1509     {
1510       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1511       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1512     }
1513   return ret.retn();
1514 }
1515
1516 /*!
1517  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1518  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1519  * array mean that the corresponding old node is no more used.
1520  *  \return DataArrayIdType * - a new instance of DataArrayIdType of length \a
1521  *           this->getNumberOfNodes() before call of this method. The caller is to
1522  *           delete this array using decrRef() as it is no more needed.
1523  *  \throw If the coordinates array is not set.
1524  *  \throw If the nodal connectivity of cells is not defined.
1525  *  \throw If the nodal connectivity includes an invalid id.
1526  *  \sa areAllNodesFetched
1527  *
1528  *  \if ENABLE_EXAMPLES
1529  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1530  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1531  *  \endif
1532  */
1533 DataArrayIdType *MEDCouplingUMesh::zipCoordsTraducer()
1534 {
1535   return MEDCouplingPointSet::zipCoordsTraducer();
1536 }
1537
1538 /*!
1539  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1540  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1541  */
1542 int MEDCouplingUMesh::AreCellsEqual(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2, int compType)
1543 {
1544   switch(compType)
1545   {
1546     case 0:
1547       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1548     case 1:
1549       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1550     case 2:
1551       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1552     case 3:
1553       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1554     case 7:
1555       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1556   }
1557   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1558 }
1559
1560 /*!
1561  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1562  */
1563 int MEDCouplingUMesh::AreCellsEqualPolicy0(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1564 {
1565   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1566     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1567   return 0;
1568 }
1569
1570 /*!
1571  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1572  */
1573 int MEDCouplingUMesh::AreCellsEqualPolicy1(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1574 {
1575   mcIdType sz=connI[cell1+1]-connI[cell1];
1576   if(sz==connI[cell2+1]-connI[cell2])
1577     {
1578       if(conn[connI[cell1]]==conn[connI[cell2]])
1579         {
1580           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1581           unsigned dim=cm.getDimension();
1582           if(dim!=3)
1583             {
1584               if(dim!=1)
1585                 {
1586                   mcIdType sz1=2*(sz-1);
1587                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1588                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1589                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1590                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1591                   return work!=tmp+sz1?1:0;
1592                 }
1593               else
1594                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1595             }
1596           else
1597             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1598         }
1599     }
1600   return 0;
1601 }
1602
1603 /*!
1604  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1605  */
1606 int MEDCouplingUMesh::AreCellsEqualPolicy2(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1607 {
1608   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1609     {
1610       if(conn[connI[cell1]]==conn[connI[cell2]])
1611         {
1612           std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1613           std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1614           return s1==s2?1:0;
1615         }
1616     }
1617   return 0;
1618 }
1619
1620 /*!
1621  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1622  */
1623 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1624 {
1625   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1626     {
1627       std::set<mcIdType> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1628       std::set<mcIdType> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1629       return s1==s2?1:0;
1630     }
1631   return 0;
1632 }
1633
1634 /*!
1635  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1636  */
1637 int MEDCouplingUMesh::AreCellsEqualPolicy7(const mcIdType *conn, const mcIdType *connI, mcIdType cell1, mcIdType cell2)
1638 {
1639   mcIdType sz=connI[cell1+1]-connI[cell1];
1640   if(sz==connI[cell2+1]-connI[cell2])
1641     {
1642       if(conn[connI[cell1]]==conn[connI[cell2]])
1643         {
1644           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1645           unsigned dim=cm.getDimension();
1646           if(dim!=3)
1647             {
1648               if(dim!=1)
1649                 {
1650                   mcIdType sz1=2*(sz-1);
1651                   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz1];
1652                   mcIdType *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(mcIdType *)tmp);
1653                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1654                   work=std::search((mcIdType *)tmp,(mcIdType *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1655                   if(work!=tmp+sz1)
1656                     return 1;
1657                   else
1658                     {
1659                       std::reverse_iterator<mcIdType *> it1((mcIdType *)tmp+sz1);
1660                       std::reverse_iterator<mcIdType *> it2((mcIdType *)tmp);
1661                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1662                         return 2;
1663                       else
1664                         return 0;
1665                     }
1666
1667                   return work!=tmp+sz1?1:0;
1668                 }
1669               else
1670                 {//case of SEG2 and SEG3
1671                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1672                     return 1;
1673                   if(!cm.isQuadratic())
1674                     {
1675                       std::reverse_iterator<const mcIdType *> it1(conn+connI[cell1+1]);
1676                       std::reverse_iterator<const mcIdType *> it2(conn+connI[cell1]+1);
1677                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1678                         return 2;
1679                       return 0;
1680                     }
1681                   else
1682                     {
1683                       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])
1684                         return 2;
1685                       return 0;
1686                     }
1687                 }
1688             }
1689           else
1690             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1691         }
1692     }
1693   return 0;
1694 }
1695
1696
1697 /*!
1698  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified by \a compType (see zipConnectivityTraducer).
1699  * This method keeps the coordinates of \a this. The comparison starts at rank \a startCellId cell id (included).
1700  * 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.
1701  * If \a startCellId is greater than 0 algorithm starts at cell #startCellId but for each cell all candidates are considered.
1702  * This method is time consuming.
1703  *
1704  * \param [in] compType input specifying the technique used to compare cells each other.
1705  *   - 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.
1706  *   - 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)
1707  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1708  *   - 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
1709  * can be used for users not sensitive to orientation of cell
1710  * \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.
1711  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1712  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1713  * \return the correspondence array old to new in a newly allocated array.
1714  *
1715  */
1716 void MEDCouplingUMesh::findCommonCells(int compType, mcIdType startCellId, DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr) const
1717 {
1718   MCAuto<DataArrayIdType> revNodal=DataArrayIdType::New(),revNodalI=DataArrayIdType::New();
1719   getReverseNodalConnectivity(revNodal,revNodalI);
1720   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1721 }
1722
1723 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, mcIdType startCellId, const DataArrayIdType *nodal, const DataArrayIdType *nodalI, const DataArrayIdType *revNodal, const DataArrayIdType *revNodalI,
1724                                           DataArrayIdType *& commonCellsArr, DataArrayIdType *& commonCellsIArr)
1725 {
1726   MCAuto<DataArrayIdType> commonCells=DataArrayIdType::New(),commonCellsI=DataArrayIdType::New(); commonCells->alloc(0,1);
1727   mcIdType nbOfCells=nodalI->getNumberOfTuples()-1;
1728   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1729   const mcIdType *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1730   const mcIdType *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1731   std::vector<bool> isFetched(nbOfCells,false);
1732   if(startCellId==0)
1733     {
1734       for(mcIdType i=startCellId;i<nbOfCells;i++)
1735         {
1736           if(!isFetched[i])
1737             {
1738               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1739               std::vector<mcIdType> v,v2;
1740               if(connOfNode!=connPtr+connIPtr[i+1])
1741                 {
1742                   const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1743                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1744                   connOfNode++;
1745                 }
1746               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1747                 if(*connOfNode>=0)
1748                   {
1749                     v=v2;
1750                     const mcIdType *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1751                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1752                     v2.resize(std::distance(v2.begin(),it));
1753                   }
1754               if(v2.size()>1)
1755                 {
1756                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1757                     {
1758                       mcIdType pos=commonCellsI->back();
1759                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1760                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1761                         isFetched[*it]=true;
1762                     }
1763                 }
1764             }
1765         }
1766     }
1767   else
1768     {
1769       for(mcIdType i=startCellId;i<nbOfCells;i++)
1770         {
1771           if(!isFetched[i])
1772             {
1773               const mcIdType *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1));
1774               // v2 contains the result of successive intersections using rev nodal on on each node of cell #i
1775               std::vector<mcIdType> v,v2;
1776               if(connOfNode!=connPtr+connIPtr[i+1])
1777                 {
1778                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1779                   connOfNode++;
1780                 }
1781               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1782                 if(*connOfNode>=0)
1783                   {
1784                     v=v2;
1785                     std::vector<mcIdType>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1786                     v2.resize(std::distance(v2.begin(),it));
1787                   }
1788               // v2 contains now candidates. Problem candidates are sorted using id rank.
1789               if(v2.size()>1)
1790                 {
1791                   if(v2[0]!=i)
1792                   {
1793                     auto it(std::find(v2.begin(),v2.end(),i));
1794                     std::swap(*v2.begin(),*it);
1795                   }
1796                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1797                     {
1798                       mcIdType newPos(commonCells->getNumberOfTuples());
1799                       mcIdType pos(commonCellsI->back());
1800                       std::sort(commonCells->getPointer()+pos,commonCells->getPointer()+newPos);
1801                       commonCellsI->pushBackSilent(newPos);
1802                       for(const mcIdType *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1803                         isFetched[*it]=true;
1804                     }
1805                 }
1806             }
1807         }
1808     }
1809   commonCellsArr=commonCells.retn();
1810   commonCellsIArr=commonCellsI.retn();
1811 }
1812
1813 /*!
1814  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1815  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1816  * than \a this->getNumberOfCells() in the returned array means that there is no
1817  * corresponding cell in \a this mesh.
1818  * It is expected that \a this and \a other meshes share the same node coordinates
1819  * array, if it is not so an exception is thrown.
1820  *  \param [in] other - the mesh to compare with.
1821  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1822  *         valid values [0,1,2], see zipConnectivityTraducer().
1823  *  \param [out] arr - a new instance of DataArrayIdType returning correspondence
1824  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1825  *         values. The caller is to delete this array using
1826  *         decrRef() as it is no more needed.
1827  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1828  *         mesh.
1829  *
1830  *  \if ENABLE_EXAMPLES
1831  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1832  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1833  *  \endif
1834  *  \sa checkDeepEquivalOnSameNodesWith()
1835  *  \sa checkGeoEquivalWith()
1836  */
1837 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayIdType *& arr) const
1838 {
1839   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1840   mcIdType nbOfCells=getNumberOfCells();
1841   static const int possibleCompType[]={0,1,2};
1842   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1843     {
1844       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1845       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1846       oss << " !";
1847       throw INTERP_KERNEL::Exception(oss.str());
1848     }
1849   MCAuto<DataArrayIdType> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1850   arr=o2n->subArray(nbOfCells);
1851   arr->setName(other->getName());
1852   mcIdType tmp;
1853   if(other->getNumberOfCells()==0)
1854     return true;
1855   return arr->getMaxValue(tmp)<nbOfCells;
1856 }
1857
1858 /*!
1859  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1860  * This method tries to determine if \b other is fully included in \b this.
1861  * The main difference is that this method is not expected to throw exception.
1862  * This method has two outputs :
1863  *
1864  * \param other other mesh
1865  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1866  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1867  */
1868 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayIdType *& arr) const
1869 {
1870   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1871   DataArrayIdType *commonCells=0,*commonCellsI=0;
1872   mcIdType thisNbCells=getNumberOfCells();
1873   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1874   MCAuto<DataArrayIdType> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1875   const mcIdType *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1876   mcIdType otherNbCells=other->getNumberOfCells();
1877   MCAuto<DataArrayIdType> arr2=DataArrayIdType::New();
1878   arr2->alloc(otherNbCells,1);
1879   arr2->fillWithZero();
1880   mcIdType *arr2Ptr=arr2->getPointer();
1881   mcIdType nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1882   for(mcIdType i=0;i<nbOfCommon;i++)
1883     {
1884       mcIdType start=commonCellsPtr[commonCellsIPtr[i]];
1885       if(start<thisNbCells)
1886         {
1887           for(mcIdType j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1888             {
1889               mcIdType sig=commonCellsPtr[j]>0?1:-1;
1890               mcIdType val=std::abs(commonCellsPtr[j])-1;
1891               if(val>=thisNbCells)
1892                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1893             }
1894         }
1895     }
1896   arr2->setName(other->getName());
1897   if(arr2->presenceOfValue(0))
1898     return false;
1899   arr=arr2.retn();
1900   return true;
1901 }
1902
1903 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1904 {
1905   if(!other)
1906     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1907   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1908   if(!otherC)
1909     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1910   std::vector<const MEDCouplingUMesh *> ms(2);
1911   ms[0]=this;
1912   ms[1]=otherC;
1913   return MergeUMeshesOnSameCoords(ms);
1914 }
1915
1916 /*!
1917  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
1918  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
1919  * cellIds is not given explicitly but by a range python like.
1920  *
1921  * \param start
1922  * \param end
1923  * \param step
1924  * \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.
1925  * \return a newly allocated
1926  *
1927  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
1928  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
1929  */
1930 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, bool keepCoords) const
1931 {
1932   if(getMeshDimension()!=-1)
1933     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
1934   else
1935     {
1936       mcIdType newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
1937       if(newNbOfCells!=1)
1938         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1939       if(start!=0)
1940         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1941       incrRef();
1942       return const_cast<MEDCouplingUMesh *>(this);
1943     }
1944 }
1945
1946 /*!
1947  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
1948  * The result mesh shares or not the node coordinates array with \a this mesh depending
1949  * on \a keepCoords parameter.
1950  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
1951  *           to write this mesh to the MED file, its cells must be sorted using
1952  *           sortCellsInMEDFileFrmt().
1953  *  \param [in] begin - an array of cell ids to include to the new mesh.
1954  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
1955  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
1956  *         array of \a this mesh, else "free" nodes are removed from the result mesh
1957  *         by calling zipCoords().
1958  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
1959  *         to delete this mesh using decrRef() as it is no more needed.
1960  *  \throw If the coordinates array is not set.
1961  *  \throw If the nodal connectivity of cells is not defined.
1962  *  \throw If any cell id in the array \a begin is not valid.
1963  *
1964  *  \if ENABLE_EXAMPLES
1965  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
1966  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
1967  *  \endif
1968  */
1969 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const mcIdType *begin, const mcIdType *end, bool keepCoords) const
1970 {
1971   if(getMeshDimension()!=-1)
1972     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
1973   else
1974     {
1975       if(end-begin!=1)
1976         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
1977       if(begin[0]!=0)
1978         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
1979       incrRef();
1980       return const_cast<MEDCouplingUMesh *>(this);
1981     }
1982 }
1983
1984 /*!
1985  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
1986  *
1987  * 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.
1988  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
1989  * The number of cells of \b this will remain the same with this method.
1990  *
1991  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
1992  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
1993  * \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 ).
1994  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
1995  */
1996 void MEDCouplingUMesh::setPartOfMySelf(const mcIdType *cellIdsBg, const mcIdType *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
1997 {
1998   checkConnectivityFullyDefined();
1999   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2000   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2001     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2002   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2003     {
2004       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2005       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2006       throw INTERP_KERNEL::Exception(oss.str());
2007     }
2008   mcIdType nbOfCellsToModify( ToIdType((std::distance(cellIdsBg,cellIdsEnd))));
2009   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2010     {
2011       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2012       throw INTERP_KERNEL::Exception(oss.str());
2013     }
2014   mcIdType nbOfCells(getNumberOfCells());
2015   bool easyAssign(true);
2016   const mcIdType *connI(_nodal_connec_index->begin());
2017   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->begin();
2018   for(const mcIdType *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2019     {
2020       if(*it>=0 && *it<nbOfCells)
2021         {
2022           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2023         }
2024       else
2025         {
2026           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2027           throw INTERP_KERNEL::Exception(oss.str());
2028         }
2029     }
2030   if(easyAssign)
2031     {
2032       DataArrayIdType::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2033       computeTypes();
2034     }
2035   else
2036     {
2037       DataArrayIdType *arrOut=0,*arrIOut=0;
2038       DataArrayIdType::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2039                                                arrOut,arrIOut);
2040       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2041       setConnectivity(arrOut,arrIOut,true);
2042     }
2043 }
2044
2045 void MEDCouplingUMesh::setPartOfMySelfSlice(mcIdType start, mcIdType end, mcIdType step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2046 {
2047   checkConnectivityFullyDefined();
2048   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2049   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2050     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2051   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2052     {
2053       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2054       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2055       throw INTERP_KERNEL::Exception(oss.str());
2056     }
2057   mcIdType nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2058   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2059     {
2060       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2061       throw INTERP_KERNEL::Exception(oss.str());
2062     }
2063   mcIdType nbOfCells=getNumberOfCells();
2064   bool easyAssign=true;
2065   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2066   const mcIdType *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2067   mcIdType it=start;
2068   for(mcIdType i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2069     {
2070       if(it>=0 && it<nbOfCells)
2071         {
2072           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2073         }
2074       else
2075         {
2076           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2077           throw INTERP_KERNEL::Exception(oss.str());
2078         }
2079     }
2080   if(easyAssign)
2081     {
2082       DataArrayIdType::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2083       computeTypes();
2084     }
2085   else
2086     {
2087       DataArrayIdType *arrOut=0,*arrIOut=0;
2088       DataArrayIdType::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2089                                                 arrOut,arrIOut);
2090       MCAuto<DataArrayIdType> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2091       setConnectivity(arrOut,arrIOut,true);
2092     }
2093 }
2094
2095
2096 /*!
2097  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2098  * this->getMeshDimension(), that bound some cells of \a this mesh.
2099  * The cells of lower dimension to include to the result mesh are selected basing on
2100  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2101  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2102  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2103  * created mesh shares the node coordinates array with \a this mesh.
2104  *  \param [in] begin - the array of node ids.
2105  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2106  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2107  *         array \a begin are added, else cells whose any node is in the
2108  *         array \a begin are added.
2109  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2110  *         to delete this mesh using decrRef() as it is no more needed.
2111  *  \throw If the coordinates array is not set.
2112  *  \throw If the nodal connectivity of cells is not defined.
2113  *  \throw If any node id in \a begin is not valid.
2114  *
2115  *  \if ENABLE_EXAMPLES
2116  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2117  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2118  *  \endif
2119  */
2120 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const mcIdType *begin, const mcIdType *end, bool fullyIn) const
2121 {
2122   MCAuto<DataArrayIdType> desc,descIndx,revDesc,revDescIndx;
2123   desc=DataArrayIdType::New(); descIndx=DataArrayIdType::New(); revDesc=DataArrayIdType::New(); revDescIndx=DataArrayIdType::New();
2124   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2125   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2126   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2127 }
2128
2129 /*!
2130  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2131  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2132  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2133  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2134  *         by calling zipCoords().
2135  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2136  *         to delete this mesh using decrRef() as it is no more needed.
2137  *  \throw If the coordinates array is not set.
2138  *  \throw If the nodal connectivity of cells is not defined.
2139  *
2140  *  \if ENABLE_EXAMPLES
2141  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2142  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2143  *  \endif
2144  */
2145 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2146 {
2147   DataArrayIdType *desc=DataArrayIdType::New();
2148   DataArrayIdType *descIndx=DataArrayIdType::New();
2149   DataArrayIdType *revDesc=DataArrayIdType::New();
2150   DataArrayIdType *revDescIndx=DataArrayIdType::New();
2151   //
2152   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2153   revDesc->decrRef();
2154   desc->decrRef();
2155   descIndx->decrRef();
2156   mcIdType nbOfCells=meshDM1->getNumberOfCells();
2157   const mcIdType *revDescIndxC=revDescIndx->getConstPointer();
2158   std::vector<mcIdType> boundaryCells;
2159   for(mcIdType i=0;i<nbOfCells;i++)
2160     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2161       boundaryCells.push_back(i);
2162   revDescIndx->decrRef();
2163   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2164   return ret;
2165 }
2166
2167 /*!
2168  * This method returns a newly created DataArrayIdType instance containing ids of cells located in boundary.
2169  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2170  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown.
2171  */
2172 DataArrayIdType *MEDCouplingUMesh::findCellIdsOnBoundary() const
2173 {
2174   checkFullyDefined();
2175   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2176   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2177   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2178   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2179   //
2180   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2181   desc=(DataArrayIdType*)0; descIndx=(DataArrayIdType*)0;
2182   //
2183   MCAuto<DataArrayIdType> tmp=revDescIndx->deltaShiftIndex();
2184   MCAuto<DataArrayIdType> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayIdType*)0;
2185   const mcIdType *revDescPtr=revDesc->getConstPointer();
2186   const mcIdType *revDescIndxPtr=revDescIndx->getConstPointer();
2187   mcIdType nbOfCells=getNumberOfCells();
2188   std::vector<bool> ret1(nbOfCells,false);
2189   mcIdType sz=0;
2190   for(const mcIdType *pt=faceIds->begin();pt!=faceIds->end();pt++)
2191     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2192       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2193   //
2194   DataArrayIdType *ret2=DataArrayIdType::New();
2195   ret2->alloc(sz,1);
2196   mcIdType *ret2Ptr=ret2->getPointer();
2197   sz=0;
2198   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2199     if(*it)
2200       *ret2Ptr++=sz;
2201   ret2->setName("BoundaryCells");
2202   return ret2;
2203 }
2204
2205 /*!
2206  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2207  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2208  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2209  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2210  *
2211  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2212  * 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
2213  * equals a cell in \b otherDimM1OnSameCoords.
2214  *
2215  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2216  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2217  *
2218  * \param [in] otherDimM1OnSameCoords
2219  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2220  * \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
2221  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2222  */
2223 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *&cellIdsRk0, DataArrayIdType *&cellIdsRk1) const
2224 {
2225   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2226     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2227   checkConnectivityFullyDefined();
2228   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2229   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2230     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2231   MCAuto<DataArrayIdType> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2232   MCAuto<DataArrayIdType> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2233   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2234   MCAuto<DataArrayIdType> descThisPart=DataArrayIdType::New(),descIThisPart=DataArrayIdType::New(),revDescThisPart=DataArrayIdType::New(),revDescIThisPart=DataArrayIdType::New();
2235   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2236   const mcIdType *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2237   DataArrayIdType *idsOtherInConsti=0;
2238   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2239   MCAuto<DataArrayIdType> idsOtherInConstiAuto(idsOtherInConsti);
2240   if(!b)
2241     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2242   std::set<mcIdType> s1;
2243   for(const mcIdType *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2244     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2245   MCAuto<DataArrayIdType> s1arr_renum1=DataArrayIdType::New(); s1arr_renum1->alloc(s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2246   s1arr_renum1->sort();
2247   cellIdsRk0=s0arr.retn();
2248   //cellIdsRk1=s_renum1.retn();
2249   cellIdsRk1=s1arr_renum1.retn();
2250 }
2251
2252 /*!
2253  * 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
2254  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2255  *
2256  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2257  */
2258 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2259 {
2260   MCAuto<DataArrayIdType> desc=DataArrayIdType::New();
2261   MCAuto<DataArrayIdType> descIndx=DataArrayIdType::New();
2262   MCAuto<DataArrayIdType> revDesc=DataArrayIdType::New();
2263   MCAuto<DataArrayIdType> revDescIndx=DataArrayIdType::New();
2264   //
2265   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2266   revDesc=0; desc=0; descIndx=0;
2267   MCAuto<DataArrayIdType> revDescIndx2=revDescIndx->deltaShiftIndex();
2268   MCAuto<DataArrayIdType> part=revDescIndx2->findIdsEqual(1);
2269   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2270 }
2271
2272 /*!
2273  * Finds nodes lying on the boundary of \a this mesh.
2274  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of found
2275  *          nodes. The caller is to delete this array using decrRef() as it is no
2276  *          more needed.
2277  *  \throw If the coordinates array is not set.
2278  *  \throw If the nodal connectivity of cells is node defined.
2279  *
2280  *  \if ENABLE_EXAMPLES
2281  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2282  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2283  *  \endif
2284  */
2285 DataArrayIdType *MEDCouplingUMesh::findBoundaryNodes() const
2286 {
2287   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2288   return skin->computeFetchedNodeIds();
2289 }
2290
2291 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2292 {
2293   incrRef();
2294   return const_cast<MEDCouplingUMesh *>(this);
2295 }
2296
2297 /*!
2298  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2299  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2300  * This method searches for nodes needed to be duplicated. These nodes are nodes fetched by \b otherDimM1OnSameCoords which are not part of the boundary of \b otherDimM1OnSameCoords.
2301  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considered as needed to be duplicated.
2302  * 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.
2303  *
2304  * \param [in] otherDimM1OnSameCoords a mesh lying on the same coords than \b this and with a mesh dimension equal to those of \b this minus 1. WARNING this input
2305  *             parameter is altered during the call.
2306  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2307  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2308  * \param [out] cellIdsNotModified cell ids mcIdType \b this that lies on \b otherDimM1OnSameCoords mesh whose connectivity do \b not need to be modified as it is the case for \b cellIdsNeededToBeRenum.
2309  *
2310  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2311  */
2312 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayIdType *& nodeIdsToDuplicate,
2313                                             DataArrayIdType *& cellIdsNeededToBeRenum, DataArrayIdType *& cellIdsNotModified) const
2314 {
2315   typedef MCAuto<DataArrayIdType> DAInt;
2316   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2317
2318   checkFullyDefined();
2319   otherDimM1OnSameCoords.checkFullyDefined();
2320   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2321     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2322   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2323     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2324
2325   // Checking star-shaped M1 group:
2326   DAInt dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2327   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2328   DAInt dsi = rdit0->deltaShiftIndex();
2329   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2330   if(idsTmp0->getNumberOfTuples())
2331     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2332   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2333
2334   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2335   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2336   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2337   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2338   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2339   dt0=DataArrayIdType::New(),dit0=DataArrayIdType::New(),rdt0=DataArrayIdType::New(),rdit0=DataArrayIdType::New();
2340   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2341   dsi = rdit0->deltaShiftIndex();
2342   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2343   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2344   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2345   // In 3D, some points on the boundary of M0 still need duplication:
2346   DAInt notDup = 0;
2347   if (getMeshDimension() == 3)
2348     {
2349       DAInt dnu1=DataArrayIdType::New(), dnu2=DataArrayIdType::New(), dnu3=DataArrayIdType::New(), dnu4=DataArrayIdType::New();
2350       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2351       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2352       DataArrayIdType * corresp=0;
2353       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2354       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2355       corresp->decrRef();
2356       if (validIds->getNumberOfTuples())
2357         {
2358           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2359           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2360           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2361           notDup = xtrem->buildSubstraction(fNodes1);
2362         }
2363       else
2364         notDup = xtrem->buildSubstraction(fNodes);
2365     }
2366   else
2367     notDup = xtrem->buildSubstraction(fNodes);
2368
2369   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2370   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2371   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2372   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2373
2374   //
2375   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2376   mcIdType nCells2 = m0Part2->getNumberOfCells();
2377   DAInt desc00=DataArrayIdType::New(),descI00=DataArrayIdType::New(),revDesc00=DataArrayIdType::New(),revDescI00=DataArrayIdType::New();
2378   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2379
2380   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2381   DataArrayIdType *tmp00=0,*tmp11=0;
2382   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2383   DAInt neighInit00(tmp00);
2384   DAInt neighIInit00(tmp11);
2385   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2386   DataArrayIdType *idsTmp=0;
2387   m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2388   DAInt ids(idsTmp);
2389   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2390   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2391   DataArrayIdType::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2392   DataArrayIdType *tmp0=0,*tmp1=0;
2393   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2394   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2395   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2396   DAInt neigh00(tmp0);
2397   DAInt neighI00(tmp1);
2398
2399   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2400   mcIdType seed = 0, nIter = 0;
2401   mcIdType nIterMax = nCells2+1; // Safety net for the loop
2402   DAInt hitCells = DataArrayIdType::New(); hitCells->alloc(nCells2);
2403   hitCells->fillWithValue(-1);
2404   DAInt cellsToModifyConn0_torenum = DataArrayIdType::New();
2405   cellsToModifyConn0_torenum->alloc(0,1);
2406   while (nIter < nIterMax)
2407     {
2408       DAInt t = hitCells->findIdsEqual(-1);
2409       if (!t->getNumberOfTuples())
2410         break;
2411       // Connex zone without the crack (to compute the next seed really)
2412       mcIdType dnu;
2413       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2414       mcIdType cnt(0);
2415       for (mcIdType * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2416         hitCells->setIJ(*ptr,0,1);
2417       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2418       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2419       cellsToModifyConn0_torenum = DataArrayIdType::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2420       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2421       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2422       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2423       DAInt intersec = nonHitCells->buildIntersection(comple);
2424       if (intersec->getNumberOfTuples())
2425         { seed = intersec->getIJ(0,0); }
2426       else
2427         { break; }
2428       nIter++;
2429     }
2430   if (nIter >= nIterMax)
2431     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2432
2433   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2434   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2435   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2436   //
2437   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2438   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2439   nodeIdsToDuplicate=dupl.retn();
2440 }
2441
2442 /*!
2443  * This method operates a modification of the connectivity and coords in \b this.
2444  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2445  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2446  * 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
2447  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2448  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2449  *
2450  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2451  *
2452  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2453  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2454  */
2455 void MEDCouplingUMesh::duplicateNodes(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd)
2456 {
2457   mcIdType nbOfNodes=getNumberOfNodes();
2458   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2459   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2460 }
2461
2462 /*!
2463  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2464  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2465  *
2466  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2467  *
2468  * \sa renumberNodesInConn
2469  */
2470 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(mcIdType offset)
2471 {
2472   checkConnectivityFullyDefined();
2473   mcIdType *conn(getNodalConnectivity()->getPointer());
2474   const mcIdType *connIndex(getNodalConnectivityIndex()->getConstPointer());
2475   mcIdType nbOfCells=getNumberOfCells();
2476   for(mcIdType i=0;i<nbOfCells;i++)
2477     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2478       {
2479         mcIdType& node=conn[iconn];
2480         if(node>=0)//avoid polyhedron separator
2481           {
2482             node+=offset;
2483           }
2484       }
2485   _nodal_connec->declareAsNew();
2486   updateTime();
2487 }
2488
2489 /*!
2490  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2491  *  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
2492  *  of a big mesh.
2493  */
2494 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<mcIdType,mcIdType>& newNodeNumbersO2N)
2495 {
2496   this->renumberNodesInConnT< INTERP_KERNEL::HashMap<mcIdType,mcIdType> >(newNodeNumbersO2N);
2497 }
2498
2499 /*!
2500  *  Same than renumberNodesInConn(const mcIdType *) except that here the format of old-to-new traducer is using map instead
2501  *  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
2502  *  of a big mesh.
2503  */
2504 void MEDCouplingUMesh::renumberNodesInConn(const std::map<mcIdType,mcIdType>& newNodeNumbersO2N)
2505 {
2506   this->renumberNodesInConnT< std::map<mcIdType,mcIdType> >(newNodeNumbersO2N);
2507 }
2508
2509 /*!
2510  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2511  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2512  * This method is a generalization of shiftNodeNumbersInConn().
2513  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2514  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2515  *         this->getNumberOfNodes(), in "Old to New" mode.
2516  *         See \ref numbering for more info on renumbering modes.
2517  *  \throw If the nodal connectivity of cells is not defined.
2518  *
2519  *  \if ENABLE_EXAMPLES
2520  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2521  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2522  *  \endif
2523  */
2524 void MEDCouplingUMesh::renumberNodesInConn(const mcIdType *newNodeNumbersO2N)
2525 {
2526   checkConnectivityFullyDefined();
2527   mcIdType *conn=getNodalConnectivity()->getPointer();
2528   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2529   mcIdType nbOfCells=getNumberOfCells();
2530   for(mcIdType i=0;i<nbOfCells;i++)
2531     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2532       {
2533         mcIdType& node=conn[iconn];
2534         if(node>=0)//avoid polyhedron separator
2535           {
2536             node=newNodeNumbersO2N[node];
2537           }
2538       }
2539   _nodal_connec->declareAsNew();
2540   updateTime();
2541 }
2542
2543 /*!
2544  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2545  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2546  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2547  *
2548  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2549  */
2550 void MEDCouplingUMesh::shiftNodeNumbersInConn(mcIdType delta)
2551 {
2552   checkConnectivityFullyDefined();
2553   mcIdType *conn=getNodalConnectivity()->getPointer();
2554   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2555   mcIdType nbOfCells=getNumberOfCells();
2556   for(mcIdType i=0;i<nbOfCells;i++)
2557     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2558       {
2559         mcIdType& node=conn[iconn];
2560         if(node>=0)//avoid polyhedron separator
2561           {
2562             node+=delta;
2563           }
2564       }
2565   _nodal_connec->declareAsNew();
2566   updateTime();
2567 }
2568
2569 /*!
2570  * This method operates a modification of the connectivity in \b this.
2571  * 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.
2572  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this
2573  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2574  * 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
2575  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2576  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2577  *
2578  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2579  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2580  *
2581  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2582  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2583  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ).
2584  */
2585 void MEDCouplingUMesh::duplicateNodesInConn(const mcIdType *nodeIdsToDuplicateBg, const mcIdType *nodeIdsToDuplicateEnd, mcIdType offset)
2586 {
2587   checkConnectivityFullyDefined();
2588   std::map<mcIdType,mcIdType> m;
2589   mcIdType val=offset;
2590   for(const mcIdType *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2591     m[*work]=val;
2592   mcIdType *conn=getNodalConnectivity()->getPointer();
2593   const mcIdType *connIndex=getNodalConnectivityIndex()->getConstPointer();
2594   mcIdType nbOfCells=getNumberOfCells();
2595   for(mcIdType i=0;i<nbOfCells;i++)
2596     for(mcIdType iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2597       {
2598         mcIdType& node=conn[iconn];
2599         if(node>=0)//avoid polyhedron separator
2600           {
2601             std::map<mcIdType,mcIdType>::iterator it=m.find(node);
2602             if(it!=m.end())
2603               node=(*it).second;
2604           }
2605       }
2606   updateTime();
2607 }
2608
2609 /*!
2610  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2611  *
2612  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2613  * After the call of this method the number of cells remains the same as before.
2614  *
2615  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2616  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2617  * be strictly in [0;this->getNumberOfCells()).
2618  *
2619  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2620  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2621  * should be contained in[0;this->getNumberOfCells()).
2622  *
2623  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2624  * \param check
2625  */
2626 void MEDCouplingUMesh::renumberCells(const mcIdType *old2NewBg, bool check)
2627 {
2628   checkConnectivityFullyDefined();
2629   mcIdType nbCells=getNumberOfCells();
2630   const mcIdType *array=old2NewBg;
2631   if(check)
2632     array=DataArrayIdType::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2633   //
2634   const mcIdType *conn=_nodal_connec->getConstPointer();
2635   const mcIdType *connI=_nodal_connec_index->getConstPointer();
2636   MCAuto<DataArrayIdType> o2n=DataArrayIdType::New(); o2n->useArray(array,false,DeallocType::C_DEALLOC,nbCells,1);
2637   MCAuto<DataArrayIdType> n2o=o2n->invertArrayO2N2N2O(nbCells);
2638   const mcIdType *n2oPtr=n2o->begin();
2639   MCAuto<DataArrayIdType> newConn=DataArrayIdType::New();
2640   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2641   newConn->copyStringInfoFrom(*_nodal_connec);
2642   MCAuto<DataArrayIdType> newConnI=DataArrayIdType::New();
2643   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2644   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2645   //
2646   mcIdType *newC=newConn->getPointer();
2647   mcIdType *newCI=newConnI->getPointer();
2648   mcIdType loc=0;
2649   newCI[0]=loc;
2650   for(mcIdType i=0;i<nbCells;i++)
2651     {
2652       mcIdType pos=n2oPtr[i];
2653       mcIdType nbOfElts=connI[pos+1]-connI[pos];
2654       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2655       loc+=nbOfElts;
2656       newCI[i+1]=loc;
2657     }
2658   //
2659   setConnectivity(newConn,newConnI);
2660   if(check)
2661     free(const_cast<mcIdType *>(array));
2662 }
2663
2664 /*!
2665  * Finds cells whose bounding boxes intersect a given bounding box.
2666  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2667  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2668  *         zMax (if in 3D).
2669  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2670  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2671  *         extent of the bounding box of cell to produce an addition to this bounding box.
2672  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids for found
2673  *         cells. The caller is to delete this array using decrRef() as it is no more
2674  *         needed.
2675  *  \throw If the coordinates array is not set.
2676  *  \throw If the nodal connectivity of cells is not defined.
2677  *
2678  *  \if ENABLE_EXAMPLES
2679  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2680  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2681  *  \endif
2682  */
2683 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2684 {
2685   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2686   if(getMeshDimension()==-1)
2687     {
2688       elems->pushBackSilent(0);
2689       return elems.retn();
2690     }
2691   int dim=getSpaceDimension();
2692   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2693   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2694   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2695   const double* coords = getCoords()->getConstPointer();
2696   mcIdType nbOfCells=getNumberOfCells();
2697   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2698     {
2699       for (int i=0; i<dim; i++)
2700         {
2701           elem_bb[i*2]=std::numeric_limits<double>::max();
2702           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2703         }
2704
2705       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2706         {
2707           mcIdType node= conn[inode];
2708           if(node>=0)//avoid polyhedron separator
2709             {
2710               for (int idim=0; idim<dim; idim++)
2711                 {
2712                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2713                     {
2714                       elem_bb[idim*2] = coords[node*dim+idim] ;
2715                     }
2716                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2717                     {
2718                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2719                     }
2720                 }
2721             }
2722         }
2723       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2724         elems->pushBackSilent(ielem);
2725     }
2726   return elems.retn();
2727 }
2728
2729 /*!
2730  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2731  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2732  * added in 'elems' parameter.
2733  */
2734 DataArrayIdType *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2735 {
2736   MCAuto<DataArrayIdType> elems=DataArrayIdType::New(); elems->alloc(0,1);
2737   if(getMeshDimension()==-1)
2738     {
2739       elems->pushBackSilent(0);
2740       return elems.retn();
2741     }
2742   int dim=getSpaceDimension();
2743   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2744   const mcIdType* conn      = getNodalConnectivity()->getConstPointer();
2745   const mcIdType* conn_index= getNodalConnectivityIndex()->getConstPointer();
2746   const double* coords = getCoords()->getConstPointer();
2747   mcIdType nbOfCells=getNumberOfCells();
2748   for ( mcIdType ielem=0; ielem<nbOfCells;ielem++ )
2749     {
2750       for (int i=0; i<dim; i++)
2751         {
2752           elem_bb[i*2]=std::numeric_limits<double>::max();
2753           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2754         }
2755
2756       for (mcIdType inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2757         {
2758           mcIdType node= conn[inode];
2759           if(node>=0)//avoid polyhedron separator
2760             {
2761               for (int idim=0; idim<dim; idim++)
2762                 {
2763                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2764                     {
2765                       elem_bb[idim*2] = coords[node*dim+idim] ;
2766                     }
2767                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2768                     {
2769                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2770                     }
2771                 }
2772             }
2773         }
2774       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2775         elems->pushBackSilent(ielem);
2776     }
2777   return elems.retn();
2778 }
2779
2780 /*!
2781  * Returns a type of a cell by its id.
2782  *  \param [in] cellId - the id of the cell of interest.
2783  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2784  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2785  */
2786 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(mcIdType cellId) const
2787 {
2788   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2789   if(cellId<_nodal_connec_index->getNbOfElems()-1)
2790     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2791   else
2792     {
2793       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2794       throw INTERP_KERNEL::Exception(oss.str());
2795     }
2796 }
2797
2798 /*!
2799  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2800  * This method does not throw exception if geometric type \a type is not in \a this.
2801  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2802  * The coordinates array is not considered here.
2803  *
2804  * \param [in] type the geometric type
2805  * \return cell ids in this having geometric type \a type.
2806  */
2807 DataArrayIdType *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2808 {
2809
2810   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
2811   ret->alloc(0,1);
2812   checkConnectivityFullyDefined();
2813   mcIdType nbCells=getNumberOfCells();
2814   int mdim=getMeshDimension();
2815   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2816   if(mdim!=ToIdType(cm.getDimension()))
2817     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2818   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2819   const mcIdType *pt=_nodal_connec->getConstPointer();
2820   for(mcIdType i=0;i<nbCells;i++)
2821     {
2822       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2823         ret->pushBackSilent(i);
2824     }
2825   return ret.retn();
2826 }
2827
2828 /*!
2829  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2830  */
2831 mcIdType MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2832 {
2833   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2834   mcIdType nbOfCells(getNumberOfCells()),ret(0);
2835   for(mcIdType i=0;i<nbOfCells;i++)
2836     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2837       ret++;
2838   return ret;
2839 }
2840
2841 /*!
2842  * Returns the nodal connectivity of a given cell.
2843  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2844  * all returned node ids can be used in getCoordinatesOfNode().
2845  *  \param [in] cellId - an id of the cell of interest.
2846  *  \param [in,out] conn - a vector where the node ids are appended. It is not
2847  *         cleared before the appending.
2848  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2849  */
2850 void MEDCouplingUMesh::getNodeIdsOfCell(mcIdType cellId, std::vector<mcIdType>& conn) const
2851 {
2852   const mcIdType *ptI(_nodal_connec_index->begin()),*pt(_nodal_connec->begin());
2853   for(const mcIdType *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2854     if(*w>=0)
2855       conn.push_back(*w);
2856 }
2857
2858 std::string MEDCouplingUMesh::simpleRepr() const
2859 {
2860   static const char msg0[]="No coordinates specified !";
2861   std::ostringstream ret;
2862   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
2863   ret << "Description of mesh : \"" << getDescription() << "\"\n";
2864   int tmpp1,tmpp2;
2865   double tt=getTime(tmpp1,tmpp2);
2866   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
2867   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
2868   if(_mesh_dim>=-1)
2869     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
2870   else
2871     { ret << " Mesh dimension has not been set or is invalid !"; }
2872   if(_coords!=0)
2873     {
2874       const int spaceDim=getSpaceDimension();
2875       ret << spaceDim << "\nInfo attached on space dimension : ";
2876       for(int i=0;i<spaceDim;i++)
2877         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
2878       ret << "\n";
2879     }
2880   else
2881     ret << msg0 << "\n";
2882   ret << "Number of nodes : ";
2883   if(_coords!=0)
2884     ret << getNumberOfNodes() << "\n";
2885   else
2886     ret << msg0 << "\n";
2887   ret << "Number of cells : ";
2888   if(_nodal_connec!=0 && _nodal_connec_index!=0)
2889     ret << getNumberOfCells() << "\n";
2890   else
2891     ret << "No connectivity specified !" << "\n";
2892   ret << "Cell types present : ";
2893   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
2894     {
2895       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
2896       ret << cm.getRepr() << " ";
2897     }
2898   ret << "\n";
2899   return ret.str();
2900 }
2901
2902 std::string MEDCouplingUMesh::advancedRepr() const
2903 {
2904   std::ostringstream ret;
2905   ret << simpleRepr();
2906   ret << "\nCoordinates array : \n___________________\n\n";
2907   if(_coords)
2908     _coords->reprWithoutNameStream(ret);
2909   else
2910     ret << "No array set !\n";
2911   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
2912   reprConnectivityOfThisLL(ret);
2913   return ret.str();
2914 }
2915
2916 /*!
2917  * This method returns a C++ code that is a dump of \a this.
2918  * This method will throw if this is not fully defined.
2919  */
2920 std::string MEDCouplingUMesh::cppRepr() const
2921 {
2922   static const char coordsName[]="coords";
2923   static const char connName[]="conn";
2924   static const char connIName[]="connI";
2925   checkFullyDefined();
2926   std::ostringstream ret; ret << "// coordinates" << std::endl;
2927   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
2928   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
2929   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
2930   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
2931   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
2932   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
2933   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
2934   return ret.str();
2935 }
2936
2937 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
2938 {
2939   std::ostringstream ret;
2940   reprConnectivityOfThisLL(ret);
2941   return ret.str();
2942 }
2943
2944 /*!
2945  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsibility to deal with.
2946  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
2947  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
2948  * some algos).
2949  *
2950  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
2951  * 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
2952  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
2953  */
2954 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(std::size_t spaceDim) const
2955 {
2956   int mdim=getMeshDimension();
2957   if(mdim<0)
2958     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
2959   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
2960   MCAuto<DataArrayIdType> tmp1,tmp2;
2961   bool needToCpyCT=true;
2962   if(!_nodal_connec)
2963     {
2964       tmp1=DataArrayIdType::New(); tmp1->alloc(0,1);
2965       needToCpyCT=false;
2966     }
2967   else
2968     {
2969       tmp1=_nodal_connec;
2970       tmp1->incrRef();
2971     }
2972   if(!_nodal_connec_index)
2973     {
2974       tmp2=DataArrayIdType::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
2975       needToCpyCT=false;
2976     }
2977   else
2978     {
2979       tmp2=_nodal_connec_index;
2980       tmp2->incrRef();
2981     }
2982   ret->setConnectivity(tmp1,tmp2,false);
2983   if(needToCpyCT)
2984     ret->_types=_types;
2985   if(!_coords)
2986     {
2987       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
2988       ret->setCoords(coords);
2989     }
2990   else
2991     ret->setCoords(_coords);
2992   return ret.retn();
2993 }
2994
2995 mcIdType MEDCouplingUMesh::getNumberOfNodesInCell(mcIdType cellId) const
2996 {
2997   const mcIdType *ptI=_nodal_connec_index->getConstPointer();
2998   const mcIdType *pt=_nodal_connec->getConstPointer();
2999   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3000     return ptI[cellId+1]-ptI[cellId]-1;
3001   else
3002     return ToIdType(std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<mcIdType>(),-1)));
3003 }
3004
3005 /*!
3006  * Returns types of cells of the specified part of \a this mesh.
3007  * This method avoids computing sub-mesh explicitly to get its types.
3008  *  \param [in] begin - an array of cell ids of interest.
3009  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3010  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3011  *         describing the cell types.
3012  *  \throw If the coordinates array is not set.
3013  *  \throw If the nodal connectivity of cells is not defined.
3014  *  \sa getAllGeoTypes()
3015  */
3016 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const mcIdType *begin, const mcIdType *end) const
3017 {
3018   checkFullyDefined();
3019   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3020   const mcIdType *conn=_nodal_connec->getConstPointer();
3021   const mcIdType *connIndex=_nodal_connec_index->getConstPointer();
3022   for(const mcIdType *w=begin;w!=end;w++)
3023     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3024   return ret;
3025 }
3026
3027 /*!
3028  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3029  * Optionally updates
3030  * a set of types of cells constituting \a this mesh.
3031  * This method is for advanced users having prepared their connectivity before. For
3032  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3033  *  \param [in] conn - the nodal connectivity array.
3034  *  \param [in] connIndex - the nodal connectivity index array.
3035  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3036  *         mesh is updated.
3037  */
3038 void MEDCouplingUMesh::setConnectivity(DataArrayIdType *conn, DataArrayIdType *connIndex, bool isComputingTypes)
3039 {
3040   DataArrayIdType::SetArrayIn(conn,_nodal_connec);
3041   DataArrayIdType::SetArrayIn(connIndex,_nodal_connec_index);
3042   if(isComputingTypes)
3043     computeTypes();
3044   declareAsNew();
3045 }
3046
3047 /*!
3048  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3049  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3050  */
3051 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCpy):MEDCouplingPointSet(other,deepCpy),_mesh_dim(other._mesh_dim),
3052     _nodal_connec(0),_nodal_connec_index(0),
3053     _types(other._types)
3054 {
3055   if(other._nodal_connec)
3056     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCpy);
3057   if(other._nodal_connec_index)
3058     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCpy);
3059 }
3060
3061 MEDCouplingUMesh::~MEDCouplingUMesh()
3062 {
3063   if(_nodal_connec)
3064     _nodal_connec->decrRef();
3065   if(_nodal_connec_index)
3066     _nodal_connec_index->decrRef();
3067 }
3068
3069 /*!
3070  * Recomputes a set of cell types of \a this mesh. For more info see
3071  * \ref MEDCouplingUMeshNodalConnectivity.
3072  */
3073 void MEDCouplingUMesh::computeTypes()
3074 {
3075   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3076 }
3077
3078
3079 /*!
3080  * Returns a number of cells constituting \a this mesh.
3081  *  \return mcIdType - the number of cells in \a this mesh.
3082  *  \throw If the nodal connectivity of cells is not defined.
3083  */
3084 mcIdType MEDCouplingUMesh::getNumberOfCells() const
3085 {
3086   if(_nodal_connec_index)
3087     return _nodal_connec_index->getNumberOfTuples()-1;
3088   else
3089     if(_mesh_dim==-1)
3090       return 1;
3091     else
3092       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3093 }
3094
3095 /*!
3096  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3097  * mesh. For more info see \ref meshes.
3098  *  \return int - the dimension of \a this mesh.
3099  *  \throw If the mesh dimension is not defined using setMeshDimension().
3100  */
3101 int MEDCouplingUMesh::getMeshDimension() const
3102 {
3103   if(_mesh_dim<-1)
3104     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3105   return _mesh_dim;
3106 }
3107
3108 /*!
3109  * Returns a length of the nodal connectivity array.
3110  * This method is for test reason. Normally the integer returned is not useable by
3111  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3112  *  \return mcIdType - the length of the nodal connectivity array.
3113  */
3114 mcIdType MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3115 {
3116   return _nodal_connec->getNbOfElems();
3117 }
3118
3119 /*!
3120  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3121  */
3122 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<mcIdType>& tinyInfo, std::vector<std::string>& littleStrings) const
3123 {
3124   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3125   tinyInfo.push_back(ToIdType(getMeshDimension()));
3126   tinyInfo.push_back(getNumberOfCells());
3127   if(_nodal_connec)
3128     tinyInfo.push_back(getNodalConnectivityArrayLen());
3129   else
3130     tinyInfo.push_back(-1);
3131 }
3132
3133 /*!
3134  * First step of unserialization process.
3135  */
3136 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<mcIdType>& tinyInfo) const
3137 {
3138   return tinyInfo[6]<=0;
3139 }
3140
3141 /*!
3142  * Second step of serialization process.
3143  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3144  * \param a1
3145  * \param a2
3146  * \param littleStrings
3147  */
3148 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<mcIdType>& tinyInfo, DataArrayIdType *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3149 {
3150   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3151   if(tinyInfo[5]!=-1)
3152     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3153 }
3154
3155 /*!
3156  * Third and final step of serialization process.
3157  */
3158 void MEDCouplingUMesh::serialize(DataArrayIdType *&a1, DataArrayDouble *&a2) const
3159 {
3160   MEDCouplingPointSet::serialize(a1,a2);
3161   if(getMeshDimension()>-1)
3162     {
3163       a1=DataArrayIdType::New();
3164       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3165       mcIdType *ptA1=a1->getPointer();
3166       const mcIdType *conn=getNodalConnectivity()->getConstPointer();
3167       const mcIdType *index=getNodalConnectivityIndex()->getConstPointer();
3168       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3169       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3170     }
3171   else
3172     a1=0;
3173 }
3174
3175 /*!
3176  * Second and final unserialization process.
3177  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3178  */
3179 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<mcIdType>& tinyInfo, const DataArrayIdType *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3180 {
3181   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3182   setMeshDimension(FromIdType<int>(tinyInfo[5]));
3183   if(tinyInfo[7]!=-1)
3184     {
3185       // Connectivity
3186       const mcIdType *recvBuffer=a1->getConstPointer();
3187       MCAuto<DataArrayIdType> myConnecIndex=DataArrayIdType::New();
3188       myConnecIndex->alloc(tinyInfo[6]+1,1);
3189       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3190       MCAuto<DataArrayIdType> myConnec=DataArrayIdType::New();
3191       myConnec->alloc(tinyInfo[7],1);
3192       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3193       setConnectivity(myConnec, myConnecIndex);
3194     }
3195 }
3196
3197
3198
3199 /*!
3200  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3201  * mesh.<br>
3202  * For 1D cells, the returned field contains lengths.<br>
3203  * For 2D cells, the returned field contains areas.<br>
3204  * For 3D cells, the returned field contains volumes.
3205  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3206  *         orientation, i.e. the volume is always positive.
3207  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3208  *         and one time . The caller is to delete this field using decrRef() as it is no
3209  *         more needed.
3210  */
3211 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3212 {
3213   std::string name="MeasureOfMesh_";
3214   name+=getName();
3215   mcIdType nbelem=getNumberOfCells();
3216   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3217   field->setName(name);
3218   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3219   array->alloc(nbelem,1);
3220   double *area_vol=array->getPointer();
3221   field->setArray(array) ; array=0;
3222   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3223   field->synchronizeTimeWithMesh();
3224   if(getMeshDimension()!=-1)
3225     {
3226       mcIdType ipt;
3227       INTERP_KERNEL::NormalizedCellType type;
3228       int dim_space=getSpaceDimension();
3229       const double *coords=getCoords()->getConstPointer();
3230       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3231       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3232       for(mcIdType iel=0;iel<nbelem;iel++)
3233         {
3234           ipt=connec_index[iel];
3235           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3236           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);
3237         }
3238       if(isAbs)
3239         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3240     }
3241   else
3242     {
3243       area_vol[0]=std::numeric_limits<double>::max();
3244     }
3245   return field.retn();
3246 }
3247
3248 /*!
3249  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3250  * mesh.<br>
3251  * For 1D cells, the returned array contains lengths.<br>
3252  * For 2D cells, the returned array contains areas.<br>
3253  * For 3D cells, the returned array contains volumes.
3254  * This method avoids building explicitly a part of \a this mesh to perform the work.
3255  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3256  *         orientation, i.e. the volume is always positive.
3257  *  \param [in] begin - an array of cell ids of interest.
3258  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3259  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3260  *          delete this array using decrRef() as it is no more needed.
3261  *
3262  *  \if ENABLE_EXAMPLES
3263  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3264  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3265  *  \endif
3266  *  \sa getMeasureField()
3267  */
3268 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const mcIdType *begin, const mcIdType *end) const
3269 {
3270   std::string name="PartMeasureOfMesh_";
3271   name+=getName();
3272   std::size_t nbelem=std::distance(begin,end);
3273   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3274   array->setName(name);
3275   array->alloc(nbelem,1);
3276   double *area_vol=array->getPointer();
3277   if(getMeshDimension()!=-1)
3278     {
3279       mcIdType ipt;
3280       INTERP_KERNEL::NormalizedCellType type;
3281       int dim_space=getSpaceDimension();
3282       const double *coords=getCoords()->getConstPointer();
3283       const mcIdType *connec=getNodalConnectivity()->getConstPointer();
3284       const mcIdType *connec_index=getNodalConnectivityIndex()->getConstPointer();
3285       for(const mcIdType *iel=begin;iel!=end;iel++)
3286         {
3287           ipt=connec_index[*iel];
3288           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3289           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3290         }
3291       if(isAbs)
3292         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3293     }
3294   else
3295     {
3296       area_vol[0]=std::numeric_limits<double>::max();
3297     }
3298   return array.retn();
3299 }
3300
3301 /*!
3302  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3303  * \a this one. The returned field contains the dual cell volume for each corresponding
3304  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3305  *  the dual mesh in P1 sens of \a this.<br>
3306  * For 1D cells, the returned field contains lengths.<br>
3307  * For 2D cells, the returned field contains areas.<br>
3308  * For 3D cells, the returned field contains volumes.
3309  * This method is useful to check "P1*" conservative interpolators.
3310  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3311  *         orientation, i.e. the volume is always positive.
3312  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3313  *          nodes and one time. The caller is to delete this array using decrRef() as
3314  *          it is no more needed.
3315  */
3316 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3317 {
3318   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3319   std::string name="MeasureOnNodeOfMesh_";
3320   name+=getName();
3321   mcIdType nbNodes=getNumberOfNodes();
3322   MCAuto<DataArrayDouble> nnpc;
3323   {
3324     MCAuto<DataArrayIdType> tmp(computeNbOfNodesPerCell());
3325     nnpc=tmp->convertToDblArr();
3326   }
3327   std::for_each(nnpc->rwBegin(),nnpc->rwEnd(),[](double& v) { v=1./v; });
3328   const double *nnpcPtr(nnpc->begin());
3329   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3330   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3331   array->alloc(nbNodes,1);
3332   double *valsToFill=array->getPointer();
3333   std::fill(valsToFill,valsToFill+nbNodes,0.);
3334   const double *values=tmp->getArray()->getConstPointer();
3335   MCAuto<DataArrayIdType> da=DataArrayIdType::New();
3336   MCAuto<DataArrayIdType> daInd=DataArrayIdType::New();
3337   getReverseNodalConnectivity(da,daInd);
3338   const mcIdType *daPtr=da->getConstPointer();
3339   const mcIdType *daIPtr=daInd->getConstPointer();
3340   for(mcIdType i=0;i<nbNodes;i++)
3341     for(const mcIdType *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3342       valsToFill[i]+=nnpcPtr[*cell]*values[*cell];
3343   ret->setMesh(this);
3344   ret->setArray(array);
3345   return ret.retn();
3346 }
3347
3348 /*!
3349  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3350  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3351  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3352  * and are normalized.
3353  * <br> \a this can be either
3354  * - a  2D mesh in 2D or 3D space or
3355  * - an 1D mesh in 2D space.
3356  *
3357  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3358  *          cells and one time. The caller is to delete this field using decrRef() as
3359  *          it is no more needed.
3360  *  \throw If the nodal connectivity of cells is not defined.
3361  *  \throw If the coordinates array is not set.
3362  *  \throw If the mesh dimension is not set.
3363  *  \throw If the mesh and space dimension is not as specified above.
3364  */
3365 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3366 {
3367   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3368     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3369   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3370   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3371   mcIdType nbOfCells=getNumberOfCells();
3372   int nbComp=getMeshDimension()+1;
3373   array->alloc(nbOfCells,nbComp);
3374   double *vals=array->getPointer();
3375   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3376   const mcIdType *conn=_nodal_connec->getConstPointer();
3377   const double *coords=_coords->getConstPointer();
3378   if(getMeshDimension()==2)
3379     {
3380       if(getSpaceDimension()==3)
3381         {
3382           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3383           const double *locPtr=loc->getConstPointer();
3384           for(mcIdType i=0;i<nbOfCells;i++,vals+=3)
3385             {
3386               mcIdType offset=connI[i];
3387               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3388               double n=INTERP_KERNEL::norm<3>(vals);
3389               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3390             }
3391         }
3392       else
3393         {
3394           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3395           const double *isAbsPtr=isAbs->getArray()->begin();
3396           for(mcIdType i=0;i<nbOfCells;i++,isAbsPtr++)
3397             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3398         }
3399     }
3400   else//meshdimension==1
3401     {
3402       double tmp[2];
3403       for(mcIdType i=0;i<nbOfCells;i++)
3404         {
3405           mcIdType offset=connI[i];
3406           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3407           double n=INTERP_KERNEL::norm<2>(tmp);
3408           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3409           *vals++=-tmp[1];
3410           *vals++=tmp[0];
3411         }
3412     }
3413   ret->setArray(array);
3414   ret->setMesh(this);
3415   ret->synchronizeTimeWithSupport();
3416   return ret.retn();
3417 }
3418
3419 /*!
3420  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3421  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3422  * and are normalized.
3423  * <br> \a this can be either
3424  * - a  2D mesh in 2D or 3D space or
3425  * - an 1D mesh in 2D space.
3426  *
3427  * This method avoids building explicitly a part of \a this mesh to perform the work.
3428  *  \param [in] begin - an array of cell ids of interest.
3429  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3430  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3431  *          cells and one time. The caller is to delete this field using decrRef() as
3432  *          it is no more needed.
3433  *  \throw If the nodal connectivity of cells is not defined.
3434  *  \throw If the coordinates array is not set.
3435  *  \throw If the mesh dimension is not set.
3436  *  \throw If the mesh and space dimension is not as specified above.
3437  *  \sa buildOrthogonalField()
3438  *
3439  *  \if ENABLE_EXAMPLES
3440  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3441  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3442  *  \endif
3443  */
3444 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const mcIdType *begin, const mcIdType *end) const
3445 {
3446   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3447     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3448   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3449   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3450   std::size_t nbelems=std::distance(begin,end);
3451   int nbComp=getMeshDimension()+1;
3452   array->alloc(nbelems,nbComp);
3453   double *vals=array->getPointer();
3454   const mcIdType *connI=_nodal_connec_index->getConstPointer();
3455   const mcIdType *conn=_nodal_connec->getConstPointer();
3456   const double *coords=_coords->getConstPointer();
3457   if(getMeshDimension()==2)
3458     {
3459       if(getSpaceDimension()==3)
3460         {
3461           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3462           const double *locPtr=loc->getConstPointer();
3463           for(const mcIdType *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3464             {
3465               mcIdType offset=connI[*i];
3466               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3467               double n=INTERP_KERNEL::norm<3>(vals);
3468               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3469             }
3470         }
3471       else
3472         {
3473           for(std::size_t i=0;i<nbelems;i++)
3474             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3475         }
3476     }
3477   else//meshdimension==1
3478     {
3479       double tmp[2];
3480       for(const mcIdType *i=begin;i!=end;i++)
3481         {
3482           mcIdType offset=connI[*i];
3483           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3484           double n=INTERP_KERNEL::norm<2>(tmp);
3485           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3486           *vals++=-tmp[1];
3487           *vals++=tmp[0];
3488         }
3489     }
3490   ret->setArray(array);
3491   ret->setMesh(this);
3492   ret->synchronizeTimeWithSupport();
3493   return ret.retn();
3494 }
3495
3496 /*!
3497  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3498  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3499  * and are \b not normalized.
3500  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3501  *          cells and one time. The caller is to delete this field using decrRef() as
3502  *          it is no more needed.
3503  *  \throw If the nodal connectivity of cells is not defined.
3504  *  \throw If the coordinates array is not set.
3505  *  \throw If \a this->getMeshDimension() != 1.
3506  *  \throw If \a this mesh includes cells of type other than SEG2.
3507  */
3508 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3509 {
3510   if(getMeshDimension()!=1)
3511     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3512   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3513     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3514   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3515   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3516   mcIdType nbOfCells=getNumberOfCells();
3517   int spaceDim=getSpaceDimension();
3518   array->alloc(nbOfCells,spaceDim);
3519   double *pt=array->getPointer();
3520   const double *coo=getCoords()->getConstPointer();
3521   std::vector<mcIdType> conn;
3522   conn.reserve(2);
3523   for(mcIdType i=0;i<nbOfCells;i++)
3524     {
3525       conn.resize(0);
3526       getNodeIdsOfCell(i,conn);
3527       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3528     }
3529   ret->setArray(array);
3530   ret->setMesh(this);
3531   ret->synchronizeTimeWithSupport();
3532   return ret.retn();
3533 }
3534
3535 /*!
3536  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3537  * returns a new DataArrayIdType, of length equal to the number of 2D cells in the result
3538  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3539  * from. If a result face is shared by two 3D cells, then the face in included twice in
3540  * the result mesh.
3541  *  \param [in] origin - 3 components of a point defining location of the plane.
3542  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3543  *         must be greater than 1e-6.
3544  *  \param [in] eps - half-thickness of the plane.
3545  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of 3D cells
3546  *         producing correspondent 2D cells. The caller is to delete this array
3547  *         using decrRef() as it is no more needed.
3548  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3549  *         not share the node coordinates array with \a this mesh. The caller is to
3550  *         delete this mesh using decrRef() as it is no more needed.
3551  *  \throw If the coordinates array is not set.
3552  *  \throw If the nodal connectivity of cells is not defined.
3553  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3554  *  \throw If magnitude of \a vec is less than 1e-6.
3555  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3556  *  \throw If \a this includes quadratic cells.
3557  */
3558 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3559 {
3560   checkFullyDefined();
3561   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3562     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3563   MCAuto<DataArrayIdType> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3564   if(candidates->empty())
3565     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3566   std::vector<mcIdType> nodes;
3567   DataArrayIdType *cellIds1D=0;
3568   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3569   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3570   MCAuto<DataArrayIdType> desc1=DataArrayIdType::New(),desc2=DataArrayIdType::New();
3571   MCAuto<DataArrayIdType> descIndx1=DataArrayIdType::New(),descIndx2=DataArrayIdType::New();
3572   MCAuto<DataArrayIdType> revDesc1=DataArrayIdType::New(),revDesc2=DataArrayIdType::New();
3573   MCAuto<DataArrayIdType> revDescIndx1=DataArrayIdType::New(),revDescIndx2=DataArrayIdType::New();
3574   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3575   revDesc2=0; revDescIndx2=0;
3576   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3577   revDesc1=0; revDescIndx1=0;
3578   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3579   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3580   //
3581   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3582   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3583     cut3DCurve[*it]=-1;
3584   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3585   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3586   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3587                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3588                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3589   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New());
3590   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3591   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3592   if(cellIds2->empty())
3593     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3594   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3595   ret->setCoords(mDesc1->getCoords());
3596   ret->setConnectivity(conn,connI,true);
3597   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3598   return ret.retn();
3599 }
3600
3601 /*!
3602  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3603 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
3604 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3605 the result mesh.
3606  *  \param [in] origin - 3 components of a point defining location of the plane.
3607  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3608  *         must be greater than 1e-6.
3609  *  \param [in] eps - half-thickness of the plane.
3610  *  \param [out] cellIds - a new instance of DataArrayIdType holding ids of faces
3611  *         producing correspondent segments. The caller is to delete this array
3612  *         using decrRef() as it is no more needed.
3613  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3614  *         mesh in 3D space. This mesh does not share the node coordinates array with
3615  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3616  *         no more needed.
3617  *  \throw If the coordinates array is not set.
3618  *  \throw If the nodal connectivity of cells is not defined.
3619  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3620  *  \throw If magnitude of \a vec is less than 1e-6.
3621  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3622  *  \throw If \a this includes quadratic cells.
3623  */
3624 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayIdType *&cellIds) const
3625 {
3626   checkFullyDefined();
3627   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3628     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3629   MCAuto<DataArrayIdType> candidates(getCellIdsCrossingPlane(origin,vec,eps));
3630   if(candidates->empty())
3631     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3632   std::vector<mcIdType> nodes;
3633   DataArrayIdType *cellIds1D(0);
3634   MCAuto<MEDCouplingUMesh> subMesh(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3635   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3636   MCAuto<DataArrayIdType> desc1(DataArrayIdType::New()),descIndx1(DataArrayIdType::New()),revDesc1(DataArrayIdType::New()),revDescIndx1(DataArrayIdType::New());
3637   MCAuto<MEDCouplingUMesh> mDesc1(subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3638   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3639   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3640   //
3641   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3642   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3643     cut3DCurve[*it]=-1;
3644   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3645   mcIdType ncellsSub=subMesh->getNumberOfCells();
3646   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(ncellsSub);
3647   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3648                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3649                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3650   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New()),cellIds2(DataArrayIdType::New()); connI->pushBackSilent(0);
3651   conn->alloc(0,1);
3652   const mcIdType *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3653   const mcIdType *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3654   for(mcIdType i=0;i<ncellsSub;i++)
3655     {
3656       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3657         {
3658           if(cut3DSurf[i].first!=-2)
3659             {
3660               conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3661               connI->pushBackSilent(conn->getNumberOfTuples());
3662               cellIds2->pushBackSilent(i);
3663             }
3664           else
3665             {
3666               mcIdType cellId3DSurf=cut3DSurf[i].second;
3667               mcIdType offset=nodalI[cellId3DSurf]+1;
3668               mcIdType nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3669               for(mcIdType j=0;j<nbOfEdges;j++)
3670                 {
3671                   conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_SEG2)); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3672                   connI->pushBackSilent(conn->getNumberOfTuples());
3673                   cellIds2->pushBackSilent(cellId3DSurf);
3674                 }
3675             }
3676         }
3677     }
3678   if(cellIds2->empty())
3679     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3680   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3681   ret->setCoords(mDesc1->getCoords());
3682   ret->setConnectivity(conn,connI,true);
3683   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3684   return ret.retn();
3685 }
3686
3687 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::clipSingle3DCellByPlane(const double origin[3], const double vec[3], double eps) const
3688 {
3689   checkFullyDefined();
3690   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3691     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3692   if(getNumberOfCells()!=1)
3693     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane works only on mesh containing exactly one cell !");
3694   //
3695   std::vector<mcIdType> nodes;
3696   findNodesOnPlane(origin,vec,eps,nodes);
3697   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());
3698   MCAuto<MEDCouplingUMesh> mDesc2(buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2));//meshDim==2 spaceDim==3
3699   revDesc2=0; revDescIndx2=0;
3700   MCAuto<MEDCouplingUMesh> mDesc1(mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));//meshDim==1 spaceDim==3
3701   revDesc1=0; revDescIndx1=0;
3702   DataArrayIdType *cellIds1D(0);
3703   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3704   MCAuto<DataArrayIdType> cellIds1DTmp(cellIds1D);
3705   std::vector<mcIdType> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3706   for(const mcIdType *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3707     cut3DCurve[*it]=-1;
3708   bool sameNbNodes;
3709   {
3710     mcIdType oldNbNodes(mDesc1->getNumberOfNodes());
3711     mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3712     sameNbNodes=(mDesc1->getNumberOfNodes()==oldNbNodes);
3713   }
3714   std::vector< std::pair<mcIdType,mcIdType> > cut3DSurf(mDesc2->getNumberOfCells());
3715   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->begin(),mDesc2->getNodalConnectivityIndex()->begin(),
3716                               mDesc1->getNodalConnectivity()->begin(),mDesc1->getNodalConnectivityIndex()->begin(),
3717                               desc1->begin(),descIndx1->begin(),cut3DSurf);
3718   MCAuto<DataArrayIdType> conn(DataArrayIdType::New()),connI(DataArrayIdType::New());
3719   connI->pushBackSilent(0); conn->alloc(0,1);
3720   {
3721     MCAuto<DataArrayIdType> cellIds2(DataArrayIdType::New()); cellIds2->alloc(0,1);
3722     assemblyForSplitFrom3DSurf(cut3DSurf,desc2->begin(),descIndx2->begin(),conn,connI,cellIds2);
3723     if(cellIds2->empty())
3724       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3725   }
3726   std::vector<std::vector<mcIdType> > res;
3727   buildSubCellsFromCut(cut3DSurf,desc2->begin(),descIndx2->begin(),mDesc1->getCoords()->begin(),eps,res);
3728   std::size_t sz(res.size());
3729   if(ToIdType(res.size())==mDesc1->getNumberOfCells() && sameNbNodes)
3730     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::clipSingle3DCellByPlane : cell is not clipped !");
3731   for(std::size_t i=0;i<sz;i++)
3732     {
3733       conn->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
3734       conn->insertAtTheEnd(res[i].begin(),res[i].end());
3735       connI->pushBackSilent(conn->getNumberOfTuples());
3736     }
3737   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
3738   ret->setCoords(mDesc1->getCoords());
3739   ret->setConnectivity(conn,connI,true);
3740   mcIdType nbCellsRet(ret->getNumberOfCells());
3741   //
3742   MCAuto<DataArrayDouble> vec2(DataArrayDouble::New()); vec2->alloc(1,3); std::copy(vec,vec+3,vec2->getPointer());
3743   MCAuto<MEDCouplingFieldDouble> ortho(ret->buildOrthogonalField());
3744   MCAuto<DataArrayDouble> ortho2(ortho->getArray()->selectByTupleIdSafeSlice(0,1,1));
3745   MCAuto<DataArrayDouble> dott(DataArrayDouble::Dot(ortho2,vec2));
3746   MCAuto<DataArrayDouble> ccm(ret->computeCellCenterOfMass());
3747   MCAuto<DataArrayDouble> occm;
3748   {
3749     MCAuto<DataArrayDouble> pt(DataArrayDouble::New()); pt->alloc(1,3); std::copy(origin,origin+3,pt->getPointer());
3750     occm=DataArrayDouble::Substract(ccm,pt);
3751   }
3752   vec2=DataArrayDouble::New(); vec2->alloc(nbCellsRet,3);
3753   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);
3754   MCAuto<DataArrayDouble> dott2(DataArrayDouble::Dot(occm,vec2));
3755   //
3756   const mcIdType *cPtr(ret->getNodalConnectivity()->begin()),*ciPtr(ret->getNodalConnectivityIndex()->begin());
3757   MCAuto<MEDCouplingUMesh> ret2(MEDCouplingUMesh::New("Clip3D",3));
3758   ret2->setCoords(mDesc1->getCoords());
3759   MCAuto<DataArrayIdType> conn2(DataArrayIdType::New()),conn2I(DataArrayIdType::New());
3760   conn2I->pushBackSilent(0); conn2->alloc(0,1);
3761   std::vector<mcIdType> cell0(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3762   std::vector<mcIdType> cell1(1,ToIdType(INTERP_KERNEL::NORM_POLYHED));
3763   if(dott->getIJ(0,0)>0)
3764     {
3765       cell0.insert(cell0.end(),cPtr+1,cPtr+ciPtr[1]);
3766       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell1,cell1.end()));
3767     }
3768   else
3769     {
3770       cell1.insert(cell1.end(),cPtr+1,cPtr+ciPtr[1]);
3771       std::reverse_copy(cPtr+1,cPtr+ciPtr[1],std::inserter(cell0,cell0.end()));
3772     }
3773   for(mcIdType i=1;i<nbCellsRet;i++)
3774     {
3775       if(dott2->getIJ(i,0)<0)
3776         {
3777           if(ciPtr[i+1]-ciPtr[i]>=4)
3778             {
3779               cell0.push_back(-1);
3780               cell0.insert(cell0.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3781             }
3782         }
3783       else
3784         {
3785           if(ciPtr[i+1]-ciPtr[i]>=4)
3786             {
3787               cell1.push_back(-1);
3788               cell1.insert(cell1.end(),cPtr+ciPtr[i]+1,cPtr+ciPtr[i+1]);
3789             }
3790         }
3791     }
3792   conn2->insertAtTheEnd(cell0.begin(),cell0.end());
3793   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3794   conn2->insertAtTheEnd(cell1.begin(),cell1.end());
3795   conn2I->pushBackSilent(conn2->getNumberOfTuples());
3796   ret2->setConnectivity(conn2,conn2I,true);
3797   ret2->checkConsistencyLight();
3798   ret2->orientCorrectlyPolyhedrons();
3799   return ret2;
3800 }
3801
3802 /*!
3803  * Finds cells whose bounding boxes intersect a given plane.
3804  *  \param [in] origin - 3 components of a point defining location of the plane.
3805  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3806  *         must be greater than 1e-6.
3807  *  \param [in] eps - half-thickness of the plane.
3808  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of the found
3809  *         cells. The caller is to delete this array using decrRef() as it is no more
3810  *         needed.
3811  *  \throw If the coordinates array is not set.
3812  *  \throw If the nodal connectivity of cells is not defined.
3813  *  \throw If \a this->getSpaceDimension() != 3.
3814  *  \throw If magnitude of \a vec is less than 1e-6.
3815  *  \sa buildSlice3D()
3816  */
3817 DataArrayIdType *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3818 {
3819   checkFullyDefined();
3820   if(getSpaceDimension()!=3)
3821     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3822   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3823   if(normm<1e-6)
3824     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3825   double vec2[3];
3826   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3827   double angle=acos(vec[2]/normm);
3828   MCAuto<DataArrayIdType> cellIds;
3829   double bbox[6];
3830   if(angle>eps)
3831     {
3832       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3833       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3834       if(normm2/normm>1e-6)
3835         DataArrayDouble::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer(),coo->getPointer());
3836       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3837       mw->setCoords(coo);
3838       mw->getBoundingBox(bbox);
3839       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3840       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3841     }
3842   else
3843     {
3844       getBoundingBox(bbox);
3845       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3846       cellIds=getCellsInBoundingBox(bbox,eps);
3847     }
3848   return cellIds.retn();
3849 }
3850
3851 /*!
3852  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
3853  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
3854  * No consideration of coordinate is done by this method.
3855  * 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)
3856  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be useful.
3857  */
3858 bool MEDCouplingUMesh::isContiguous1D() const
3859 {
3860   if(getMeshDimension()!=1)
3861     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
3862   mcIdType nbCells=getNumberOfCells();
3863   if(nbCells<1)
3864     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
3865   const mcIdType *connI(_nodal_connec_index->begin()),*conn(_nodal_connec->begin());
3866   mcIdType ref=conn[connI[0]+2];
3867   for(mcIdType i=1;i<nbCells;i++)
3868     {
3869       if(conn[connI[i]+1]!=ref)
3870         return false;
3871       ref=conn[connI[i]+2];
3872     }
3873   return true;
3874 }
3875
3876 /*!
3877  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
3878  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
3879  * \param pt reference point of the line
3880  * \param v normalized director vector of the line
3881  * \param eps max precision before throwing an exception
3882  * \param res output of size this->getNumberOfCells
3883  */
3884 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
3885 {
3886   if(getMeshDimension()!=1)
3887     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
3888   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3889     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
3890   if(getSpaceDimension()!=3)
3891     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
3892   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
3893   const double *fPtr=f->getArray()->getConstPointer();
3894   double tmp[3];
3895   for(mcIdType i=0;i<getNumberOfCells();i++)
3896     {
3897       const double *tmp1=fPtr+3*i;
3898       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
3899       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
3900       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
3901       double n1=INTERP_KERNEL::norm<3>(tmp);
3902       n1/=INTERP_KERNEL::norm<3>(tmp1);
3903       if(n1>eps)
3904         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
3905     }
3906   const double *coo=getCoords()->getConstPointer();
3907   for(mcIdType i=0;i<getNumberOfNodes();i++)
3908     {
3909       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
3910       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
3911       res[i]=std::accumulate(tmp,tmp+3,0.);
3912     }
3913 }
3914
3915 /*!
3916  * 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.
3917  * \a this is expected to be a mesh so that its space dimension is equal to its
3918  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3919  * 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).
3920  *
3921  * 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
3922  * 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).
3923  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3924  *
3925  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
3926  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3927  *
3928  * \param [in] ptBg the start pointer (included) of the coordinates of the point
3929  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
3930  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
3931  * \return the positive value of the distance.
3932  * \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
3933  * dimension - 1.
3934  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
3935  */
3936 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, mcIdType& cellId) const
3937 {
3938   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3939   if(meshDim!=spaceDim-1)
3940     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
3941   if(meshDim!=2 && meshDim!=1)
3942     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
3943   checkFullyDefined();
3944   if(ToIdType(std::distance(ptBg,ptEnd))!=spaceDim)
3945     { 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()); }
3946   DataArrayIdType *ret1=0;
3947   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,DeallocType::C_DEALLOC,1,spaceDim);
3948   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
3949   MCAuto<DataArrayIdType> ret1Safe(ret1);
3950   cellId=*ret1Safe->begin();
3951   return *ret0->begin();
3952 }
3953
3954 /*!
3955  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
3956  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance.
3957  * 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
3958  * 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).
3959  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
3960  *
3961  * \a this is expected to be a mesh so that its space dimension is equal to its
3962  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
3963  * 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).
3964  *
3965  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
3966  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
3967  *
3968  * \param [in] pts the list of points in which each tuple represents a point
3969  * \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.
3970  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
3971  * \throw if number of components of \a pts is not equal to the space dimension.
3972  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
3973  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
3974  */
3975 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayIdType *& cellIds) const
3976 {
3977   if(!pts)
3978     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
3979   pts->checkAllocated();
3980   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
3981   if(meshDim!=spaceDim-1)
3982     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
3983   if(meshDim!=2 && meshDim!=1)
3984     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
3985   if(ToIdType(pts->getNumberOfComponents())!=spaceDim)
3986     {
3987       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
3988       throw INTERP_KERNEL::Exception(oss.str());
3989     }
3990   checkFullyDefined();
3991   mcIdType nbCells=getNumberOfCells();
3992   if(nbCells==0)
3993     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
3994   mcIdType nbOfPts=pts->getNumberOfTuples();
3995   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
3996   MCAuto<DataArrayIdType> ret1=DataArrayIdType::New(); ret1->alloc(nbOfPts,1);
3997   const mcIdType *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
3998   double *ret0Ptr=ret0->getPointer(); mcIdType *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
3999   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4000   const double *bbox(bboxArr->begin());
4001   switch(spaceDim)
4002   {
4003     case 3:
4004       {
4005         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4006         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4007           {
4008             double x=std::numeric_limits<double>::max();
4009             std::vector<mcIdType> elems;
4010             myTree.getMinDistanceOfMax(ptsPtr,x);
4011             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4012             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4013           }
4014         break;
4015       }
4016     case 2:
4017       {
4018         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4019         for(mcIdType i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4020           {
4021             double x=std::numeric_limits<double>::max();
4022             std::vector<mcIdType> elems;
4023             myTree.getMinDistanceOfMax(ptsPtr,x);
4024             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4025             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4026           }
4027         break;
4028       }
4029     default:
4030       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4031   }
4032   cellIds=ret1.retn();
4033   return ret0.retn();
4034 }
4035
4036 /// @cond INTERNAL
4037
4038 /// @endcond
4039
4040 /*!
4041  * Finds cells in contact with a ball (i.e. a point with precision).
4042  * 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.
4043  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4044  *
4045  * \warning This method is suitable if the caller intends to evaluate only one
4046  *          point, for more points getCellsContainingPoints() is recommended as it is
4047  *          faster.
4048  *  \param [in] pos - array of coordinates of the ball central point.
4049  *  \param [in] eps - ball radius.
4050  *  \return mcIdType - a smallest id of cells being in contact with the ball, -1 in case
4051  *         if there are no such cells.
4052  *  \throw If the coordinates array is not set.
4053  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4054  */
4055 mcIdType MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4056 {
4057   std::vector<mcIdType> elts;
4058   getCellsContainingPoint(pos,eps,elts);
4059   if(elts.empty())
4060     return -1;
4061   return elts.front();
4062 }
4063
4064 /*!
4065  * Finds cells in contact with a ball (i.e. a point with precision).
4066  * 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.
4067  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4068  * \warning This method is suitable if the caller intends to evaluate only one
4069  *          point, for more points getCellsContainingPoints() is recommended as it is
4070  *          faster.
4071  *  \param [in] pos - array of coordinates of the ball central point.
4072  *  \param [in] eps - ball radius.
4073  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4074  *         before inserting ids.
4075  *  \throw If the coordinates array is not set.
4076  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4077  *
4078  *  \if ENABLE_EXAMPLES
4079  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4080  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4081  *  \endif
4082  */
4083 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<mcIdType>& elts) const
4084 {
4085   MCAuto<DataArrayIdType> eltsUg,eltsIndexUg;
4086   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4087   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4088 }
4089
4090 void MEDCouplingUMesh::getCellsContainingPointsZeAlg(const double *pos, mcIdType nbOfPoints, double eps,
4091                                                      MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex,
4092                                                      std::function<bool(INTERP_KERNEL::NormalizedCellType,mcIdType)> sensibilityTo2DQuadraticLinearCellsFunc) const
4093 {
4094   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
4095   if(spaceDim==3)
4096     {
4097       if(mDim==3)
4098         {
4099           const double *coords=_coords->getConstPointer();
4100           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4101         }
4102       else
4103         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4104     }
4105   else if(spaceDim==2)
4106     {
4107       if(mDim==2)
4108         {
4109           const double *coords=_coords->getConstPointer();
4110           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4111         }
4112       else
4113         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4114     }
4115   else if(spaceDim==1)
4116     {
4117       if(mDim==1)
4118         {
4119           const double *coords=_coords->getConstPointer();
4120           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex,sensibilityTo2DQuadraticLinearCellsFunc);
4121         }
4122       else
4123         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4124     }
4125   else
4126     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4127 }
4128
4129 /*!
4130  * Finds cells in contact with several balls (i.e. points with precision).
4131  * This method is an extension of getCellContainingPoint() and
4132  * getCellsContainingPoint() for the case of multiple points.
4133  * 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.
4134  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4135  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4136  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4137  *         this->getSpaceDimension() * \a nbOfPoints
4138  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4139  *  \param [in] eps - radius of balls (i.e. the precision).
4140  *  \param [out] elts - vector returning ids of found cells.
4141  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4142  *         dividing cell ids in \a elts into groups each referring to one
4143  *         point. Its every element (except the last one) is an index pointing to the
4144  *         first id of a group of cells. For example cells in contact with the *i*-th
4145  *         point are described by following range of indices:
4146  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4147  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4148  *         Number of cells in contact with the *i*-th point is
4149  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4150  *  \throw If the coordinates array is not set.
4151  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4152  *
4153  *  \if ENABLE_EXAMPLES
4154  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4155  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4156  *  \endif
4157  */
4158 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, mcIdType nbOfPoints, double eps,
4159                                                 MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4160 {
4161   auto yesImSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType ct, int mdim) { return INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic() && mdim == 2; } );
4162   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,yesImSensibleTo2DQuadraticLinearCellsFunc);
4163 }
4164
4165 /*!
4166  * Behaves like MEDCouplingMesh::getCellsContainingPoints for cells in \a this that are linear.
4167  * For quadratic cells in \a this, this method behaves by just considering linear part of cells.
4168  * This method is here only for backward compatibility (interpolation GaussPoints to GaussPoints).
4169  * 
4170  * \sa MEDCouplingUMesh::getCellsContainingPoints, MEDCouplingRemapper::prepareNotInterpKernelOnlyGaussGauss
4171  */
4172 void MEDCouplingUMesh::getCellsContainingPointsLinearPartOnlyOnNonDynType(const double *pos, mcIdType nbOfPoints, double eps, MCAuto<DataArrayIdType>& elts, MCAuto<DataArrayIdType>& eltsIndex) const
4173 {
4174   auto noImNotSensibleTo2DQuadraticLinearCellsFunc([](INTERP_KERNEL::NormalizedCellType,mcIdType) { return false; } );
4175   this->getCellsContainingPointsZeAlg(pos,nbOfPoints,eps,elts,eltsIndex,noImNotSensibleTo2DQuadraticLinearCellsFunc);
4176 }
4177
4178 /*!
4179  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4180  * least two its edges intersect each other anywhere except their extremities. An
4181  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4182  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4183  *         cleared before filling in.
4184  *  \param [in] eps - precision.
4185  *  \throw If \a this->getMeshDimension() != 2.
4186  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4187  */
4188 void MEDCouplingUMesh::checkButterflyCells(std::vector<mcIdType>& cells, double eps) const
4189 {
4190   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4191   if(getMeshDimension()!=2)
4192     throw INTERP_KERNEL::Exception(msg);
4193   int spaceDim=getSpaceDimension();
4194   if(spaceDim!=2 && spaceDim!=3)
4195     throw INTERP_KERNEL::Exception(msg);
4196   const mcIdType *conn=_nodal_connec->getConstPointer();
4197   const mcIdType *connI=_nodal_connec_index->getConstPointer();
4198   mcIdType nbOfCells=getNumberOfCells();
4199   std::vector<double> cell2DinS2;
4200   for(mcIdType i=0;i<nbOfCells;i++)
4201     {
4202       mcIdType offset=connI[i];
4203       mcIdType nbOfNodesForCell=connI[i+1]-offset-1;
4204       if(nbOfNodesForCell<=3)
4205         continue;
4206       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4207       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4208       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4209         cells.push_back(i);
4210       cell2DinS2.clear();
4211     }
4212 }
4213
4214 /*!
4215  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4216  *
4217  * 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.
4218  * 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.
4219  *
4220  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4221  * This convex envelop is computed using Jarvis march algorithm.
4222  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4223  * 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)
4224  * 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.
4225  *
4226  * \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.
4227  * \sa MEDCouplingUMesh::colinearize2D
4228  */
4229 DataArrayIdType *MEDCouplingUMesh::convexEnvelop2D()
4230 {
4231   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4232     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4233   checkFullyDefined();
4234   const double *coords=getCoords()->getConstPointer();
4235   mcIdType nbOfCells=getNumberOfCells();
4236   MCAuto<DataArrayIdType> nodalConnecIndexOut=DataArrayIdType::New();
4237   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4238   MCAuto<DataArrayIdType> nodalConnecOut(DataArrayIdType::New());
4239   mcIdType *workIndexOut=nodalConnecIndexOut->getPointer();
4240   *workIndexOut=0;
4241   const mcIdType *nodalConnecIn=_nodal_connec->getConstPointer();
4242   const mcIdType *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4243   std::set<INTERP_KERNEL::NormalizedCellType> types;
4244   MCAuto<DataArrayIdType> isChanged(DataArrayIdType::New());
4245   isChanged->alloc(0,1);
4246   for(mcIdType i=0;i<nbOfCells;i++,workIndexOut++)
4247     {
4248       mcIdType pos=nodalConnecOut->getNumberOfTuples();
4249       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4250         isChanged->pushBackSilent(i);
4251       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4252       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4253     }
4254   if(isChanged->empty())
4255     return 0;
4256   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4257   _types=types;
4258   return isChanged.retn();
4259 }
4260
4261 /*!
4262  * This method is \b NOT const because it can modify \a this.
4263  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4264  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4265  * \param policy specifies the type of extrusion chosen:
4266  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4267  *   will be repeated to build each level
4268  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4269  *   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
4270  *   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
4271  *   arc.
4272  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.
4273  */
4274 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4275 {
4276   checkFullyDefined();
4277   mesh1D->checkFullyDefined();
4278   if(!mesh1D->isContiguous1D())
4279     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4280   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4281     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4282   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4283     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4284   if(mesh1D->getMeshDimension()!=1)
4285     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4286   bool isQuad=false;
4287   if(isPresenceOfQuadratic())
4288     {
4289       if(mesh1D->isFullyQuadratic())
4290         isQuad=true;
4291       else
4292         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4293     }
4294   mcIdType oldNbOfNodes(getNumberOfNodes());
4295   MCAuto<DataArrayDouble> newCoords;
4296   switch(policy)
4297   {
4298     case 0:
4299       {
4300         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4301         break;
4302       }
4303     case 1:
4304       {
4305         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4306         break;
4307       }
4308     default:
4309       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4310   }
4311   setCoords(newCoords);
4312   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4313   updateTime();
4314   return ret.retn();
4315 }
4316
4317
4318 /*!
4319  * Checks if \a this mesh is constituted by only quadratic cells.
4320  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
4321  *  \throw If the coordinates array is not set.
4322  *  \throw If the nodal connectivity of cells is not defined.
4323  */
4324 bool MEDCouplingUMesh::isFullyQuadratic() const
4325 {
4326   checkFullyDefined();
4327   bool ret=true;
4328   mcIdType nbOfCells=getNumberOfCells();
4329   for(mcIdType i=0;i<nbOfCells && ret;i++)
4330     {
4331       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4332       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4333       ret=cm.isQuadratic();
4334     }
4335   return ret;
4336 }
4337
4338 /*!
4339  * Checks if \a this mesh includes any quadratic cell.
4340  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
4341  *  \throw If the coordinates array is not set.
4342  *  \throw If the nodal connectivity of cells is not defined.
4343  */
4344 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
4345 {
4346   checkFullyDefined();
4347   bool ret=false;
4348   mcIdType nbOfCells=getNumberOfCells();
4349   for(mcIdType i=0;i<nbOfCells && !ret;i++)
4350     {
4351       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4352       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4353       ret=cm.isQuadratic();
4354     }
4355   return ret;
4356 }
4357
4358 /*!
4359  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
4360  * this mesh, it remains unchanged.
4361  *  \throw If the coordinates array is not set.
4362  *  \throw If the nodal connectivity of cells is not defined.
4363  */
4364 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
4365 {
4366   checkFullyDefined();
4367   mcIdType nbOfCells=getNumberOfCells();
4368   mcIdType delta=0;
4369   const mcIdType *iciptr=_nodal_connec_index->begin();
4370   for(mcIdType i=0;i<nbOfCells;i++)
4371     {
4372       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
4373       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4374       if(cm.isQuadratic())
4375         {
4376           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4377           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4378           if(!cml.isDynamic())
4379             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
4380           else
4381             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
4382         }
4383     }
4384   if(delta==0)
4385     return ;
4386   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New());
4387   const mcIdType *icptr(_nodal_connec->begin());
4388   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
4389   newConnI->alloc(nbOfCells+1,1);
4390   mcIdType *ocptr(newConn->getPointer()),*ociptr(newConnI->getPointer());
4391   *ociptr=0;
4392   _types.clear();
4393   for(mcIdType i=0;i<nbOfCells;i++,ociptr++)
4394     {
4395       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
4396       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
4397       if(!cm.isQuadratic())
4398         {
4399           _types.insert(type);
4400           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
4401           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
4402         }
4403       else
4404         {
4405           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
4406           _types.insert(typel);
4407           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
4408           mcIdType newNbOfNodes=cml.getNumberOfNodes();
4409           if(cml.isDynamic())
4410             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
4411           *ocptr++=ToIdType(typel);
4412           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
4413           ociptr[1]=ociptr[0]+newNbOfNodes+1;
4414         }
4415     }
4416   setConnectivity(newConn,newConnI,false);
4417 }
4418
4419 /*!
4420  * This method converts all linear cell in \a this to quadratic one.
4421  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
4422  * 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)
4423  * 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.
4424  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
4425  * end of the existing coordinates.
4426  *
4427  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
4428  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
4429  * \return a newly created DataArrayIdType instance that the caller should deal with containing cell ids of converted cells.
4430  *
4431  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
4432  *
4433  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
4434  */
4435 DataArrayIdType *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
4436 {
4437   DataArrayIdType *conn=0,*connI=0;
4438   DataArrayDouble *coords=0;
4439   std::set<INTERP_KERNEL::NormalizedCellType> types;
4440   checkFullyDefined();
4441   MCAuto<DataArrayIdType> ret,connSafe,connISafe;
4442   MCAuto<DataArrayDouble> coordsSafe;
4443   int meshDim=getMeshDimension();
4444   switch(conversionType)
4445   {
4446     case 0:
4447       switch(meshDim)
4448       {
4449         case 1:
4450           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
4451           connSafe=conn; connISafe=connI; coordsSafe=coords;
4452           break;
4453         case 2:
4454           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
4455           connSafe=conn; connISafe=connI; coordsSafe=coords;
4456           break;
4457         case 3:
4458           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
4459           connSafe=conn; connISafe=connI; coordsSafe=coords;
4460           break;
4461         default:
4462           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
4463       }
4464       break;
4465         case 1:
4466           {
4467             switch(meshDim)
4468             {
4469               case 1:
4470                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
4471                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4472                 break;
4473               case 2:
4474                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
4475                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4476                 break;
4477               case 3:
4478                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
4479                 connSafe=conn; connISafe=connI; coordsSafe=coords;
4480                 break;
4481               default:
4482                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
4483             }
4484             break;
4485           }
4486         default:
4487           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
4488   }
4489   setConnectivity(connSafe,connISafe,false);
4490   _types=types;
4491   setCoords(coordsSafe);
4492   return ret.retn();
4493 }
4494
4495 /*!
4496  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
4497  * so that the number of cells remains the same. Quadratic faces are converted to
4498  * polygons. This method works only for 2D meshes in
4499  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
4500  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
4501  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
4502  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
4503  *         a polylinized edge constituting the input polygon.
4504  *  \throw If the coordinates array is not set.
4505  *  \throw If the nodal connectivity of cells is not defined.
4506  *  \throw If \a this->getMeshDimension() != 2.
4507  *  \throw If \a this->getSpaceDimension() != 2.
4508  */
4509 void MEDCouplingUMesh::tessellate2D(double eps)
4510 {
4511   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
4512   if(spaceDim!=2)
4513     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
4514   switch(meshDim)
4515     {
4516     case 1:
4517       return tessellate2DCurveInternal(eps);
4518     case 2:
4519       return tessellate2DInternal(eps);
4520     default:
4521       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
4522     }
4523 }
4524
4525 #if 0
4526 /*!
4527  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
4528  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
4529  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
4530  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
4531  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
4532  * This method can be seen as the opposite method of colinearize2D.
4533  * 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
4534  * to avoid to modify the numbering of existing nodes.
4535  *
4536  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
4537  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
4538  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
4539  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
4540  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
4541  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
4542  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
4543  *
4544  * \sa buildDescendingConnectivity2
4545  */
4546 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayIdType *nodeIdsToAdd, const DataArrayIdType *nodeIdsIndexToAdd, const DataArrayIdType *edgeIdsToBeSplit,
4547                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *revDesc, const DataArrayIdType *revDescI)
4548 {
4549   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
4550     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
4551   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
4552   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
4553     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
4554   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
4555     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
4556   //DataArrayIdType *out0(0),*outi0(0);
4557   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
4558   //MCAuto<DataArrayIdType> out0s(out0),outi0s(outi0);
4559   //out0s=out0s->buildUnique(); out0s->sort(true);
4560 }
4561 #endif
4562
4563
4564 /*!
4565  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
4566  * In addition, returns an array mapping new cells to old ones. <br>
4567  * This method typically increases the number of cells in \a this mesh
4568  * but the number of nodes remains \b unchanged.
4569  * That's why the 3D splitting policies
4570  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
4571  *  \param [in] policy - specifies a pattern used for splitting.
4572  * The semantic of \a policy is:
4573  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
4574  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
4575  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4576  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
4577  *
4578  *
4579  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding, for each new cell,
4580  *          an id of old cell producing it. The caller is to delete this array using
4581  *         decrRef() as it is no more needed.
4582  *
4583  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
4584  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
4585  *          and \a this->getMeshDimension() != 3.
4586  *  \throw If \a policy is not one of the four discussed above.
4587  *  \throw If the nodal connectivity of cells is not defined.
4588  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
4589  */
4590 DataArrayIdType *MEDCouplingUMesh::simplexize(int policy)
4591 {
4592   switch(policy)
4593   {
4594     case 0:
4595       return simplexizePol0();
4596     case 1:
4597       return simplexizePol1();
4598     case INTERP_KERNEL::PLANAR_FACE_5:
4599         return simplexizePlanarFace5();
4600     case INTERP_KERNEL::PLANAR_FACE_6:
4601         return simplexizePlanarFace6();
4602     default:
4603       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)");
4604   }
4605 }
4606
4607 /*!
4608  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
4609  * - 1D: INTERP_KERNEL::NORM_SEG2
4610  * - 2D: INTERP_KERNEL::NORM_TRI3
4611  * - 3D: INTERP_KERNEL::NORM_TETRA4.
4612  *
4613  * This method is useful for users that need to use P1 field services as
4614  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
4615  * All these methods need mesh support containing only simplex cells.
4616  *  \return bool - \c true if there are only simplex cells in \a this mesh.
4617  *  \throw If the coordinates array is not set.
4618  *  \throw If the nodal connectivity of cells is not defined.
4619  *  \throw If \a this->getMeshDimension() < 1.
4620  */
4621 bool MEDCouplingUMesh::areOnlySimplexCells() const
4622 {
4623   checkFullyDefined();
4624   int mdim=getMeshDimension();
4625   if(mdim<1 || mdim>3)
4626     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
4627   mcIdType nbCells=getNumberOfCells();
4628   const mcIdType *conn=_nodal_connec->begin();
4629   const mcIdType *connI=_nodal_connec_index->begin();
4630   for(mcIdType i=0;i<nbCells;i++)
4631     {
4632       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4633       if(!cm.isSimplex())
4634         return false;
4635     }
4636   return true;
4637 }
4638
4639
4640
4641 /*!
4642  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
4643  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
4644  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell.
4645  * Quadratic cells in 2D are also handled. In those cells edges where start=end=midpoint are removed.
4646  * This method does \b not perform geometrical checks and checks only nodal connectivity of cells,
4647  * so it can be useful to call mergeNodes() before calling this method.
4648  *  \throw If \a this->getMeshDimension() <= 1.
4649  *  \throw If the coordinates array is not set.
4650  *  \throw If the nodal connectivity of cells is not defined.
4651  */
4652 void MEDCouplingUMesh::convertDegeneratedCells()
4653 {
4654   checkFullyDefined();
4655   if(getMeshDimension()<=1)
4656     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4657   mcIdType nbOfCells=getNumberOfCells();
4658   if(nbOfCells<1)
4659     return ;
4660   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4661   mcIdType *conn=_nodal_connec->getPointer();
4662   mcIdType *index=_nodal_connec_index->getPointer();
4663   mcIdType posOfCurCell=0;
4664   mcIdType newPos=0;
4665   mcIdType lgthOfCurCell;
4666   for(mcIdType i=0;i<nbOfCells;i++)
4667     {
4668       lgthOfCurCell=index[i+1]-posOfCurCell;
4669       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4670       mcIdType newLgth;
4671       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4672                                                                                                      conn+newPos+1,newLgth);
4673       conn[newPos]=newType;
4674       newPos+=newLgth+1;
4675       posOfCurCell=index[i+1];
4676       index[i+1]=newPos;
4677     }
4678   if(newPos!=initMeshLgth)
4679     _nodal_connec->reAlloc(newPos);
4680   computeTypes();
4681 }
4682
4683 /*!
4684  * Same as MEDCouplingUMesh::convertDegeneratedCells() plus deletion of the flat cells.
4685  * A cell is flat in the following cases:
4686  *   - for a linear cell, all points in the connectivity are equal
4687  *   - for a quadratic cell, either the above, or a quadratic polygon with two (linear) points and two
4688  *   identical quadratic points
4689  * \return a new instance of DataArrayIdType holding ids of removed cells. The caller is to delete
4690  *      this array using decrRef() as it is no more needed.
4691  */
4692 DataArrayIdType *MEDCouplingUMesh::convertDegeneratedCellsAndRemoveFlatOnes()
4693 {
4694   checkFullyDefined();
4695   if(getMeshDimension()<=1)
4696     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
4697   mcIdType nbOfCells=getNumberOfCells();
4698   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
4699   if(nbOfCells<1)
4700     return ret.retn();
4701   mcIdType initMeshLgth=getNodalConnectivityArrayLen();
4702   mcIdType *conn=_nodal_connec->getPointer();
4703   mcIdType *index=_nodal_connec_index->getPointer();
4704   mcIdType posOfCurCell=0;
4705   mcIdType newPos=0;
4706   mcIdType lgthOfCurCell, nbDelCells(0);
4707   for(mcIdType i=0;i<nbOfCells;i++)
4708     {
4709       lgthOfCurCell=index[i+1]-posOfCurCell;
4710       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
4711       mcIdType newLgth;
4712       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
4713                                                                                                      conn+newPos+1,newLgth);
4714       // Shall we delete the cell if it is completely degenerated:
4715       bool delCell=INTERP_KERNEL::CellSimplify::isFlatCell(conn, newPos, newLgth, newType);
4716       if (delCell)
4717         {
4718           nbDelCells++;
4719           ret->pushBackSilent(i);
4720         }
4721       else   //if the cell is to be deleted, simply stay at the same place
4722         {
4723           conn[newPos]=newType;
4724           newPos+=newLgth+1;
4725         }
4726       posOfCurCell=index[i+1];
4727       index[i+1-nbDelCells]=newPos;
4728     }
4729   if(newPos!=initMeshLgth)
4730     _nodal_connec->reAlloc(newPos);
4731   const mcIdType nCellDel=ret->getNumberOfTuples();
4732   if (nCellDel)
4733     _nodal_connec_index->reAlloc(nbOfCells-nCellDel+1);
4734   computeTypes();
4735   return ret.retn();
4736 }
4737
4738 /*!
4739  * This method remove null 1D cells from \a this. A 1D cell is considered null if start node is equal to end node.
4740  * Only connectivity is considered here.
4741  */
4742 bool MEDCouplingUMesh::removeDegenerated1DCells()
4743 {
4744   checkConnectivityFullyDefined();
4745   if(getMeshDimension()!=1)
4746     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::removeDegenerated1DCells works on umeshes with meshdim equals to 1 !");
4747   std::size_t nbCells(getNumberOfCells()),newSize(0),newSize2(0);
4748   const mcIdType *conn(getNodalConnectivity()->begin()),*conni(getNodalConnectivityIndex()->begin());
4749   {
4750     for(std::size_t i=0;i<nbCells;i++)
4751       {
4752         INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[conni[i]]);
4753         if(ct==INTERP_KERNEL::NORM_SEG2 || ct==INTERP_KERNEL::NORM_SEG3)
4754           {
4755             if(conn[conni[i]+1]!=conn[conni[i]+2])
4756               {
4757                 newSize++;
4758                 newSize2+=conni[i+1]-conni[i];
4759               }
4760           }
4761         else
4762           {
4763             std::ostringstream oss; oss << "MEDCouplingUMesh::removeDegenerated1DCells : cell #" << i << " in this is not of type SEG2/SEG3 !";
4764             throw INTERP_KERNEL::Exception(oss.str());
4765           }
4766       }
4767   }
4768   if(newSize==nbCells)//no cells has been removed -> do nothing
4769     return false;
4770   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()),newConnI(DataArrayIdType::New()); newConnI->alloc(newSize+1,1); newConn->alloc(newSize2,1);
4771   mcIdType *newConnPtr(newConn->getPointer()),*newConnIPtr(newConnI->getPointer()); newConnIPtr[0]=0;
4772   for(std::size_t i=0;i<nbCells;i++)
4773     {
4774       if(conn[conni[i]+1]!=conn[conni[i]+2])
4775         {
4776           newConnIPtr[1]=newConnIPtr[0]+conni[i+1]-conni[i];
4777           newConnPtr=std::copy(conn+conni[i],conn+conni[i+1],newConnPtr);
4778           newConnIPtr++;
4779         }
4780     }
4781   setConnectivity(newConn,newConnI,true);
4782   return true;
4783 }
4784
4785 /*!
4786  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
4787  * A cell is considered to be oriented correctly if an angle between its
4788  * normal vector and a given vector is less than \c PI / \c 2.
4789  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4790  *         cells.
4791  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4792  *         checked.
4793  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4794  *         is not cleared before filling in.
4795  *  \throw If \a this->getMeshDimension() != 2.
4796  *  \throw If \a this->getSpaceDimension() != 3.
4797  *
4798  *  \if ENABLE_EXAMPLES
4799  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4800  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4801  *  \endif
4802  */
4803 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<mcIdType>& cells) const
4804 {
4805   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4806     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
4807   mcIdType nbOfCells=getNumberOfCells();
4808   const mcIdType *conn=_nodal_connec->begin();
4809   const mcIdType *connI=_nodal_connec_index->begin();
4810   const double *coordsPtr=_coords->begin();
4811   for(mcIdType i=0;i<nbOfCells;i++)
4812     {
4813       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4814       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4815         {
4816           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
4817           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4818             cells.push_back(i);
4819         }
4820     }
4821 }
4822
4823 /*!
4824  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
4825  * considered to be oriented correctly if an angle between its normal vector and a
4826  * given vector is less than \c PI / \c 2.
4827  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
4828  *         cells.
4829  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
4830  *         checked.
4831  *  \throw If \a this->getMeshDimension() != 2.
4832  *  \throw If \a this->getSpaceDimension() != 3.
4833  *
4834  *  \if ENABLE_EXAMPLES
4835  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
4836  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
4837  *  \endif
4838  *
4839  *  \sa changeOrientationOfCells
4840  */
4841 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
4842 {
4843   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
4844     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
4845   mcIdType nbOfCells=getNumberOfCells();
4846   mcIdType *conn(_nodal_connec->getPointer());
4847   const mcIdType *connI(_nodal_connec_index->begin());
4848   const double *coordsPtr(_coords->begin());
4849   bool isModified(false);
4850   for(mcIdType i=0;i<nbOfCells;i++)
4851     {
4852       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4853       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
4854         {
4855           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4856           bool isQuadratic(cm.isQuadratic());
4857           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4858             {
4859               isModified=true;
4860               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4861             }
4862         }
4863     }
4864   if(isModified)
4865     _nodal_connec->declareAsNew();
4866   updateTime();
4867 }
4868
4869 /*!
4870  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
4871  *
4872  * \sa orientCorrectly2DCells
4873  */
4874 void MEDCouplingUMesh::changeOrientationOfCells()
4875 {
4876   int mdim(getMeshDimension());
4877   if(mdim!=2 && mdim!=1)
4878     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
4879   mcIdType nbOfCells=getNumberOfCells();
4880   mcIdType *conn(_nodal_connec->getPointer());
4881   const mcIdType *connI(_nodal_connec_index->begin());
4882   if(mdim==2)
4883     {//2D
4884       for(mcIdType i=0;i<nbOfCells;i++)
4885         {
4886           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4887           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4888           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4889         }
4890     }
4891   else
4892     {//1D
4893       for(mcIdType i=0;i<nbOfCells;i++)
4894         {
4895           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
4896           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
4897           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
4898         }
4899     }
4900 }
4901
4902 /*!
4903  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
4904  * oriented facets. The normal vector of the facet should point out of the cell.
4905  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
4906  *         is not cleared before filling in.
4907  *  \throw If \a this->getMeshDimension() != 3.
4908  *  \throw If \a this->getSpaceDimension() != 3.
4909  *  \throw If the coordinates array is not set.
4910  *  \throw If the nodal connectivity of cells is not defined.
4911  *
4912  *  \if ENABLE_EXAMPLES
4913  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4914  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4915  *  \endif
4916  */
4917 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<mcIdType>& cells) const
4918 {
4919   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4920     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
4921   mcIdType nbOfCells=getNumberOfCells();
4922   const mcIdType *conn=_nodal_connec->begin();
4923   const mcIdType *connI=_nodal_connec_index->begin();
4924   const double *coordsPtr=_coords->begin();
4925   for(mcIdType i=0;i<nbOfCells;i++)
4926     {
4927       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4928       if(type==INTERP_KERNEL::NORM_POLYHED)
4929         {
4930           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4931             cells.push_back(i);
4932         }
4933     }
4934 }
4935
4936 /*!
4937  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
4938  * out of the cell.
4939  *  \throw If \a this->getMeshDimension() != 3.
4940  *  \throw If \a this->getSpaceDimension() != 3.
4941  *  \throw If the coordinates array is not set.
4942  *  \throw If the nodal connectivity of cells is not defined.
4943  *  \throw If the reparation fails.
4944  *
4945  *  \if ENABLE_EXAMPLES
4946  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
4947  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
4948  *  \endif
4949  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
4950  */
4951 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
4952 {
4953   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
4954     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
4955   mcIdType nbOfCells=getNumberOfCells();
4956   mcIdType *conn=_nodal_connec->getPointer();
4957   const mcIdType *connI=_nodal_connec_index->begin();
4958   const double *coordsPtr=_coords->begin();
4959   for(mcIdType i=0;i<nbOfCells;i++)
4960     {
4961       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
4962       if(type==INTERP_KERNEL::NORM_POLYHED)
4963         {
4964           try
4965           {
4966               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
4967                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
4968           }
4969           catch(INTERP_KERNEL::Exception& e)
4970           {
4971               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
4972               throw INTERP_KERNEL::Exception(oss.str());
4973           }
4974         }
4975     }
4976   updateTime();
4977 }
4978
4979 /*!
4980  * This method invert orientation of all cells in \a this.
4981  * After calling this method the absolute value of measure of cells in \a this are the same than before calling.
4982  * This method only operates on the connectivity so coordinates are not touched at all.
4983  */
4984 void MEDCouplingUMesh::invertOrientationOfAllCells()
4985 {
4986   checkConnectivityFullyDefined();
4987   std::set<INTERP_KERNEL::NormalizedCellType> gts(getAllGeoTypes());
4988   mcIdType *conn(_nodal_connec->getPointer());
4989   const mcIdType *conni(_nodal_connec_index->begin());
4990   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator gt=gts.begin();gt!=gts.end();gt++)
4991     {
4992       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::OrientationInverter> oi(INTERP_KERNEL::OrientationInverter::BuildInstanceFrom(*gt));
4993       MCAuto<DataArrayIdType> cwt(giveCellsWithType(*gt));
4994       for(const mcIdType *it=cwt->begin();it!=cwt->end();it++)
4995         oi->operate(conn+conni[*it]+1,conn+conni[*it+1]);
4996     }
4997   updateTime();
4998 }
4999
5000 /*!
5001  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
5002  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
5003  * according to which the first facet of the cell should be oriented to have the normal vector
5004  * pointing out of cell.
5005  *  \return DataArrayIdType * - a new instance of DataArrayIdType holding ids of fixed
5006  *         cells. The caller is to delete this array using decrRef() as it is no more
5007  *         needed.
5008  *  \throw If \a this->getMeshDimension() != 3.
5009  *  \throw If \a this->getSpaceDimension() != 3.
5010  *  \throw If the coordinates array is not set.
5011  *  \throw If the nodal connectivity of cells is not defined.
5012  *
5013  *  \if ENABLE_EXAMPLES
5014  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
5015  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
5016  *  \endif
5017  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
5018  */
5019 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
5020 {
5021   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
5022   if(getMeshDimension()!=3)
5023     throw INTERP_KERNEL::Exception(msg);
5024   int spaceDim=getSpaceDimension();
5025   if(spaceDim!=3)
5026     throw INTERP_KERNEL::Exception(msg);
5027   //
5028   mcIdType nbOfCells=getNumberOfCells();
5029   mcIdType *conn=_nodal_connec->getPointer();
5030   const mcIdType *connI=_nodal_connec_index->begin();
5031   const double *coo=getCoords()->begin();
5032   MCAuto<DataArrayIdType> cells(DataArrayIdType::New()); cells->alloc(0,1);
5033   for(mcIdType i=0;i<nbOfCells;i++)
5034     {
5035       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5036       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
5037         {
5038           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
5039             {
5040               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5041               cells->pushBackSilent(i);
5042             }
5043         }
5044     }
5045   return cells.retn();
5046 }
5047
5048 /*!
5049  * This method is a faster method to correct orientation of all 3D cells in \a this.
5050  * 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.
5051  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
5052  *
5053  * \return a newly allocated mcIdType array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
5054  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons,
5055  */
5056 DataArrayIdType *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
5057 {
5058   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
5059     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
5060   mcIdType nbOfCells=getNumberOfCells();
5061   mcIdType *conn=_nodal_connec->getPointer();
5062   const mcIdType *connI=_nodal_connec_index->begin();
5063   const double *coordsPtr=_coords->begin();
5064   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(0,1);
5065   for(mcIdType i=0;i<nbOfCells;i++)
5066     {
5067       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
5068       switch(type)
5069       {
5070         case INTERP_KERNEL::NORM_TETRA4:
5071           {
5072             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5073               {
5074                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
5075                 ret->pushBackSilent(i);
5076               }
5077             break;
5078           }
5079         case INTERP_KERNEL::NORM_PYRA5:
5080           {
5081             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5082               {
5083                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
5084                 ret->pushBackSilent(i);
5085               }
5086             break;
5087           }
5088         case INTERP_KERNEL::NORM_PENTA6:
5089         case INTERP_KERNEL::NORM_HEXA8:
5090         case INTERP_KERNEL::NORM_HEXGP12:
5091           {
5092             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5093               {
5094                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
5095                 ret->pushBackSilent(i);
5096               }
5097             break;
5098           }
5099         case INTERP_KERNEL::NORM_POLYHED:
5100           {
5101             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
5102               {
5103                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
5104                 ret->pushBackSilent(i);
5105               }
5106             break;
5107           }
5108         default:
5109           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 !");
5110       }
5111     }
5112   updateTime();
5113   return ret.retn();
5114 }
5115
5116 /*!
5117  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
5118  * If it is not the case an exception will be thrown.
5119  * This method is fast because the first cell of \a this is used to compute the plane.
5120  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
5121  * \param pos output of size at least 3 used to store a point owned of searched plane.
5122  */
5123 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
5124 {
5125   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
5126     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
5127   const mcIdType *conn=_nodal_connec->begin();
5128   const mcIdType *connI=_nodal_connec_index->begin();
5129   const double *coordsPtr=_coords->begin();
5130   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
5131   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
5132 }
5133
5134 /*!
5135  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
5136  * cells. Currently cells of the following types are treated:
5137  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5138  * For a cell of other type an exception is thrown.
5139  * Space dimension of a 2D mesh can be either 2 or 3.
5140  * The Edge Ratio of a cell \f$t\f$ is:
5141  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
5142  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
5143  *  the smallest edge lengths of \f$t\f$.
5144  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5145  *          cells and one time, lying on \a this mesh. The caller is to delete this
5146  *          field using decrRef() as it is no more needed.
5147  *  \throw If the coordinates array is not set.
5148  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5149  *  \throw If the connectivity data array has more than one component.
5150  *  \throw If the connectivity data array has a named component.
5151  *  \throw If the connectivity index data array has more than one component.
5152  *  \throw If the connectivity index data array has a named component.
5153  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5154  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5155  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5156  */
5157 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
5158 {
5159   checkConsistencyLight();
5160   int spaceDim=getSpaceDimension();
5161   int meshDim=getMeshDimension();
5162   if(spaceDim!=2 && spaceDim!=3)
5163     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
5164   if(meshDim!=2 && meshDim!=3)
5165     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
5166   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5167   ret->setMesh(this);
5168   mcIdType nbOfCells=getNumberOfCells();
5169   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5170   arr->alloc(nbOfCells,1);
5171   double *pt=arr->getPointer();
5172   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5173   const mcIdType *conn=_nodal_connec->begin();
5174   const mcIdType *connI=_nodal_connec_index->begin();
5175   const double *coo=_coords->begin();
5176   double tmp[12];
5177   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5178     {
5179       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5180       switch(t)
5181       {
5182         case INTERP_KERNEL::NORM_TRI3:
5183           {
5184             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5185             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
5186             break;
5187           }
5188         case INTERP_KERNEL::NORM_QUAD4:
5189           {
5190             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5191             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
5192             break;
5193           }
5194         case INTERP_KERNEL::NORM_TETRA4:
5195           {
5196             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5197             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
5198             break;
5199           }
5200         default:
5201           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5202       }
5203       conn+=connI[i+1]-connI[i];
5204     }
5205   ret->setName("EdgeRatio");
5206   ret->synchronizeTimeWithSupport();
5207   return ret.retn();
5208 }
5209
5210 /*!
5211  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
5212  * cells. Currently cells of the following types are treated:
5213  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
5214  * For a cell of other type an exception is thrown.
5215  * Space dimension of a 2D mesh can be either 2 or 3.
5216  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5217  *          cells and one time, lying on \a this mesh. The caller is to delete this
5218  *          field using decrRef() as it is no more needed.
5219  *  \throw If the coordinates array is not set.
5220  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5221  *  \throw If the connectivity data array has more than one component.
5222  *  \throw If the connectivity data array has a named component.
5223  *  \throw If the connectivity index data array has more than one component.
5224  *  \throw If the connectivity index data array has a named component.
5225  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
5226  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
5227  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5228  */
5229 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
5230 {
5231   checkConsistencyLight();
5232   int spaceDim=getSpaceDimension();
5233   int meshDim=getMeshDimension();
5234   if(spaceDim!=2 && spaceDim!=3)
5235     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
5236   if(meshDim!=2 && meshDim!=3)
5237     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
5238   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5239   ret->setMesh(this);
5240   mcIdType nbOfCells=getNumberOfCells();
5241   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5242   arr->alloc(nbOfCells,1);
5243   double *pt=arr->getPointer();
5244   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5245   const mcIdType *conn=_nodal_connec->begin();
5246   const mcIdType *connI=_nodal_connec_index->begin();
5247   const double *coo=_coords->begin();
5248   double tmp[12];
5249   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5250     {
5251       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5252       switch(t)
5253       {
5254         case INTERP_KERNEL::NORM_TRI3:
5255           {
5256             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
5257             *pt=INTERP_KERNEL::triAspectRatio(tmp);
5258             break;
5259           }
5260         case INTERP_KERNEL::NORM_QUAD4:
5261           {
5262             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5263             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
5264             break;
5265           }
5266         case INTERP_KERNEL::NORM_TETRA4:
5267           {
5268             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
5269             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
5270             break;
5271           }
5272         default:
5273           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
5274       }
5275       conn+=connI[i+1]-connI[i];
5276     }
5277   ret->setName("AspectRatio");
5278   ret->synchronizeTimeWithSupport();
5279   return ret.retn();
5280 }
5281
5282 /*!
5283  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
5284  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
5285  * in 3D space. Currently only cells of the following types are
5286  * treated: INTERP_KERNEL::NORM_QUAD4.
5287  * For a cell of other type an exception is thrown.
5288  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
5289  * Defining
5290  * \f$t=\vec{da}\times\vec{ab}\f$,
5291  * \f$u=\vec{ab}\times\vec{bc}\f$
5292  * \f$v=\vec{bc}\times\vec{cd}\f$
5293  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
5294  *  \f[
5295  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
5296  *  \f]
5297  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5298  *          cells and one time, lying on \a this mesh. The caller is to delete this
5299  *          field using decrRef() as it is no more needed.
5300  *  \throw If the coordinates array is not set.
5301  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5302  *  \throw If the connectivity data array has more than one component.
5303  *  \throw If the connectivity data array has a named component.
5304  *  \throw If the connectivity index data array has more than one component.
5305  *  \throw If the connectivity index data array has a named component.
5306  *  \throw If \a this->getMeshDimension() != 2.
5307  *  \throw If \a this->getSpaceDimension() != 3.
5308  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5309  */
5310 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
5311 {
5312   checkConsistencyLight();
5313   int spaceDim=getSpaceDimension();
5314   int meshDim=getMeshDimension();
5315   if(spaceDim!=3)
5316     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
5317   if(meshDim!=2)
5318     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
5319   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5320   ret->setMesh(this);
5321   mcIdType nbOfCells=getNumberOfCells();
5322   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5323   arr->alloc(nbOfCells,1);
5324   double *pt=arr->getPointer();
5325   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5326   const mcIdType *conn=_nodal_connec->begin();
5327   const mcIdType *connI=_nodal_connec_index->begin();
5328   const double *coo=_coords->begin();
5329   double tmp[12];
5330   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5331     {
5332       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5333       switch(t)
5334       {
5335         case INTERP_KERNEL::NORM_QUAD4:
5336           {
5337             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5338             *pt=INTERP_KERNEL::quadWarp(tmp);
5339             break;
5340           }
5341         default:
5342           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
5343       }
5344       conn+=connI[i+1]-connI[i];
5345     }
5346   ret->setName("Warp");
5347   ret->synchronizeTimeWithSupport();
5348   return ret.retn();
5349 }
5350
5351
5352 /*!
5353  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
5354  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
5355  * treated: INTERP_KERNEL::NORM_QUAD4.
5356  * The skew is computed as follow for a quad with points (a,b,c,d): let
5357  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
5358  * then the skew is computed as:
5359  *  \f[
5360  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
5361  *  \f]
5362  *
5363  * For a cell of other type an exception is thrown.
5364  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
5365  *          cells and one time, lying on \a this mesh. The caller is to delete this
5366  *          field using decrRef() as it is no more needed.
5367  *  \throw If the coordinates array is not set.
5368  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
5369  *  \throw If the connectivity data array has more than one component.
5370  *  \throw If the connectivity data array has a named component.
5371  *  \throw If the connectivity index data array has more than one component.
5372  *  \throw If the connectivity index data array has a named component.
5373  *  \throw If \a this->getMeshDimension() != 2.
5374  *  \throw If \a this->getSpaceDimension() != 3.
5375  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
5376  */
5377 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
5378 {
5379   checkConsistencyLight();
5380   int spaceDim=getSpaceDimension();
5381   int meshDim=getMeshDimension();
5382   if(spaceDim!=3)
5383     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
5384   if(meshDim!=2)
5385     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
5386   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
5387   ret->setMesh(this);
5388   mcIdType nbOfCells=getNumberOfCells();
5389   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
5390   arr->alloc(nbOfCells,1);
5391   double *pt=arr->getPointer();
5392   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
5393   const mcIdType *conn=_nodal_connec->begin();
5394   const mcIdType *connI=_nodal_connec_index->begin();
5395   const double *coo=_coords->begin();
5396   double tmp[12];
5397   for(mcIdType i=0;i<nbOfCells;i++,pt++)
5398     {
5399       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
5400       switch(t)
5401       {
5402         case INTERP_KERNEL::NORM_QUAD4:
5403           {
5404             FillInCompact3DMode(3,4,conn+1,coo,tmp);
5405             *pt=INTERP_KERNEL::quadSkew(tmp);
5406             break;
5407           }
5408         default:
5409           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
5410       }
5411       conn+=connI[i+1]-connI[i];
5412     }
5413   ret->setName("Skew");
5414   ret->synchronizeTimeWithSupport();
5415   return ret.retn();
5416 }
5417
5418 /*!
5419  * 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.
5420  *
5421  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
5422  *
5423  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
5424  */
5425 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
5426 {
5427   checkConsistencyLight();
5428   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
5429   ret->setMesh(this);
5430   std::set<INTERP_KERNEL::NormalizedCellType> types;
5431   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
5432   int spaceDim(getSpaceDimension());
5433   mcIdType nbCells(getNumberOfCells());
5434   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
5435   arr->alloc(nbCells,1);
5436   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
5437     {
5438       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
5439       MCAuto<DataArrayIdType> cellIds(giveCellsWithType(*it));
5440       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
5441     }
5442   ret->setArray(arr);
5443   ret->setName("Diameter");
5444   return ret.retn();
5445 }
5446
5447 /*!
5448  * This method aggregate the bbox of each cell and put it into bbox parameter (xmin,xmax,ymin,ymax,zmin,zmax).
5449  *
5450  * \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)
5451  *                         For all other cases this input parameter is ignored.
5452  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5453  *
5454  * \throw If \a this is not fully set (coordinates and connectivity).
5455  * \throw If a cell in \a this has no valid nodeId.
5456  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5457  */
5458 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
5459 {
5460   int mDim(getMeshDimension()),sDim(getSpaceDimension());
5461   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.
5462     return getBoundingBoxForBBTreeFast();
5463   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
5464     {
5465       bool presenceOfQuadratic(false);
5466       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
5467         {
5468           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
5469           if(cm.isQuadratic())
5470             presenceOfQuadratic=true;
5471         }
5472       if(!presenceOfQuadratic)
5473         return getBoundingBoxForBBTreeFast();
5474       if(mDim==2 && sDim==2)
5475         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
5476       else
5477         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
5478     }
5479   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) !");
5480 }
5481
5482 /*!
5483  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
5484  * So meshes having quadratic cells the computed bounding boxes can be invalid !
5485  *
5486  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5487  *
5488  * \throw If \a this is not fully set (coordinates and connectivity).
5489  * \throw If a cell in \a this has no valid nodeId.
5490  */
5491 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
5492 {
5493   checkFullyDefined();
5494   int spaceDim(getSpaceDimension());
5495   mcIdType nbOfCells(getNumberOfCells()), nbOfNodes(getNumberOfNodes());
5496   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5497   double *bbox(ret->getPointer());
5498   for(mcIdType i=0;i<nbOfCells*spaceDim;i++)
5499     {
5500       bbox[2*i]=std::numeric_limits<double>::max();
5501       bbox[2*i+1]=-std::numeric_limits<double>::max();
5502     }
5503   const double *coordsPtr(_coords->begin());
5504   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5505   for(mcIdType i=0;i<nbOfCells;i++)
5506     {
5507       mcIdType offset=connI[i]+1;
5508       mcIdType nbOfNodesForCell(connI[i+1]-offset),kk(0);
5509       for(mcIdType j=0;j<nbOfNodesForCell;j++)
5510         {
5511           mcIdType nodeId=conn[offset+j];
5512           if(nodeId>=0 && nodeId<nbOfNodes)
5513             {
5514               for(int k=0;k<spaceDim;k++)
5515                 {
5516                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
5517                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
5518                 }
5519               kk++;
5520             }
5521         }
5522       if(kk==0)
5523         {
5524           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
5525           throw INTERP_KERNEL::Exception(oss.str());
5526         }
5527     }
5528   return ret.retn();
5529 }
5530
5531 /*!
5532  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
5533  * useful for 2D meshes having quadratic cells
5534  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5535  * the two extremities of the arc of circle).
5536  *
5537  * \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)
5538  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5539  * \throw If \a this is not fully defined.
5540  * \throw If \a this is not a mesh with meshDimension equal to 2.
5541  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5542  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
5543  */
5544 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
5545 {
5546   checkFullyDefined();
5547   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5548
5549   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5550   mcIdType nbOfCells=getNumberOfCells();
5551   if(spaceDim!=2 || mDim!=2)
5552     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!");
5553   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5554   double *bbox(ret->getPointer());
5555   const double *coords(_coords->begin());
5556   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5557   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5558     {
5559       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5560       mcIdType sz(connI[1]-connI[0]-1);
5561       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5562       INTERP_KERNEL::QuadraticPolygon *pol(0);
5563       for(mcIdType j=0;j<sz;j++)
5564         {
5565           mcIdType nodeId(conn[*connI+1+j]);
5566           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5567         }
5568       if(!cm.isQuadratic())
5569         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
5570       else
5571         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
5572       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
5573       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax();
5574     }
5575   return ret.retn();
5576 }
5577
5578 /*!
5579  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
5580  * useful for 2D meshes having quadratic cells
5581  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
5582  * the two extremities of the arc of circle).
5583  *
5584  * \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)
5585  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
5586  * \throw If \a this is not fully defined.
5587  * \throw If \a this is not a mesh with meshDimension equal to 1.
5588  * \throw If \a this is not a mesh with spaceDimension equal to 2.
5589  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
5590  */
5591 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
5592 {
5593   checkFullyDefined();
5594   int spaceDim(getSpaceDimension()),mDim(getMeshDimension());
5595   mcIdType nbOfCells=getNumberOfCells();
5596   if(spaceDim!=2 || mDim!=1)
5597     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!");
5598   INTERP_KERNEL::QuadraticPlanarPrecision arcPrec(arcDetEps);
5599   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
5600   double *bbox(ret->getPointer());
5601   const double *coords(_coords->begin());
5602   const mcIdType *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
5603   for(mcIdType i=0;i<nbOfCells;i++,bbox+=4,connI++)
5604     {
5605       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
5606       mcIdType sz(connI[1]-connI[0]-1);
5607       std::vector<INTERP_KERNEL::Node *> nodes(sz);
5608       INTERP_KERNEL::Edge *edge(0);
5609       for(mcIdType j=0;j<sz;j++)
5610         {
5611           mcIdType nodeId(conn[*connI+1+j]);
5612           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
5613         }
5614       if(!cm.isQuadratic())
5615         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
5616       else
5617         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
5618       const INTERP_KERNEL::Bounds& b(edge->getBounds());
5619       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
5620     }
5621   return ret.retn();
5622 }
5623
5624 /// @cond INTERNAL
5625
5626 namespace MEDCouplingImpl
5627 {
5628   class ConnReader
5629   {
5630   public:
5631     ConnReader(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5632     bool operator() (const mcIdType& pos) { return _conn[pos]!=_val; }
5633   private:
5634     const mcIdType *_conn;
5635     mcIdType _val;
5636   };
5637
5638   class ConnReader2
5639   {
5640   public:
5641     ConnReader2(const mcIdType *c, mcIdType val):_conn(c),_val(val) { }
5642     bool operator() (const mcIdType& pos) { return _conn[pos]==_val; }
5643   private:
5644     const mcIdType *_conn;
5645     mcIdType _val;
5646   };
5647 }
5648
5649 /// @endcond
5650
5651 /*!
5652  * This method expects that \a this is sorted by types. If not an exception will be thrown.
5653  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
5654  * \a this is composed in cell types.
5655  * The returned array is of size 3*n where n is the number of different types present in \a this.
5656  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here.
5657  * This parameter is kept only for compatibility with other method listed above.
5658  */
5659 std::vector<mcIdType> MEDCouplingUMesh::getDistributionOfTypes() const
5660 {
5661   checkConnectivityFullyDefined();
5662   const mcIdType *conn=_nodal_connec->begin();
5663   const mcIdType *connI=_nodal_connec_index->begin();
5664   const mcIdType *work=connI;
5665   mcIdType nbOfCells=getNumberOfCells();
5666   std::size_t n=getAllGeoTypes().size();
5667   std::vector<mcIdType> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
5668   std::set<INTERP_KERNEL::NormalizedCellType> types;
5669   for(std::size_t i=0;work!=connI+nbOfCells;i++)
5670     {
5671       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
5672       if(types.find(typ)!=types.end())
5673         {
5674           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
5675           oss << " is not contiguous !";
5676           throw INTERP_KERNEL::Exception(oss.str());
5677         }
5678       types.insert(typ);
5679       ret[3*i]=typ;
5680       const mcIdType *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
5681       ret[3*i+1]=ToIdType(std::distance(work,work2));
5682       work=work2;
5683     }
5684   return ret;
5685 }
5686
5687 /*!
5688  * This method is used to check that this has contiguous cell type in same order than described in \a code.
5689  * only for types cell, type node is not managed.
5690  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
5691  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
5692  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
5693  * If 2 or more same geometric type is in \a code and exception is thrown too.
5694  *
5695  * This method firstly checks
5696  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
5697  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
5698  * an exception is thrown too.
5699  *
5700  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
5701  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown
5702  * and a DataArrayIdType instance is returned that the user has the responsibility to deallocate.
5703  */
5704 DataArrayIdType *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<mcIdType>& code, const std::vector<const DataArrayIdType *>& idsPerType) const
5705 {
5706   if(code.empty())
5707     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
5708   std::size_t sz=code.size();
5709   std::size_t n=sz/3;
5710   if(sz%3!=0)
5711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
5712   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5713   mcIdType nb=0;
5714   bool isNoPflUsed=true;
5715   for(std::size_t i=0;i<n;i++)
5716     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
5717       {
5718         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
5719         nb+=code[3*i+1];
5720         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
5721           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
5722         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
5723       }
5724   if(types.size()!=n)
5725     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
5726   if(isNoPflUsed)
5727     {
5728       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
5729         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
5730       if(types.size()==_types.size())
5731         return 0;
5732     }
5733   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
5734   ret->alloc(nb,1);
5735   mcIdType *retPtr=ret->getPointer();
5736   const mcIdType *connI=_nodal_connec_index->begin();
5737   const mcIdType *conn=_nodal_connec->begin();
5738   mcIdType nbOfCells=getNumberOfCells();
5739   const mcIdType *i=connI;
5740   int kk=0;
5741   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
5742     {
5743       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,ToIdType((*it))));
5744       mcIdType offset=ToIdType(std::distance(connI,i));
5745       const mcIdType *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType((*it))));
5746       mcIdType nbOfCellsOfCurType=ToIdType(std::distance(i,j));
5747       if(code[3*kk+2]==-1)
5748         for(mcIdType k=0;k<nbOfCellsOfCurType;k++)
5749           *retPtr++=k+offset;
5750       else
5751         {
5752           mcIdType idInIdsPerType=code[3*kk+2];
5753           if(idInIdsPerType>=0 && idInIdsPerType<ToIdType(idsPerType.size()))
5754             {
5755               const DataArrayIdType *zePfl=idsPerType[idInIdsPerType];
5756               if(zePfl)
5757                 {
5758                   zePfl->checkAllocated();
5759                   if(zePfl->getNumberOfComponents()==1)
5760                     {
5761                       for(const mcIdType *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
5762                         {
5763                           if(*k>=0 && *k<nbOfCellsOfCurType)
5764                             *retPtr=(*k)+offset;
5765                           else
5766                             {
5767                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
5768                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
5769                               throw INTERP_KERNEL::Exception(oss.str());
5770                             }
5771                         }
5772                     }
5773                   else
5774                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
5775                 }
5776               else
5777                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
5778             }
5779           else
5780             {
5781               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
5782               oss << " should be in [0," << idsPerType.size() << ") !";
5783               throw INTERP_KERNEL::Exception(oss.str());
5784             }
5785         }
5786       i=j;
5787     }
5788   return ret.retn();
5789 }
5790
5791 /*!
5792  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
5793  * 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.
5794  * 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.
5795  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
5796  *
5797  * \param [in] profile
5798  * \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.
5799  * \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,
5800  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
5801  * \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.
5802  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
5803  * \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
5804  */
5805 void MEDCouplingUMesh::splitProfilePerType(const DataArrayIdType *profile, std::vector<mcIdType>& code, std::vector<DataArrayIdType *>& idsInPflPerType, std::vector<DataArrayIdType *>& idsPerType, bool smartPflKiller) const
5806 {
5807   if(!profile)
5808     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
5809   if(profile->getNumberOfComponents()!=1)
5810     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
5811   checkConnectivityFullyDefined();
5812   const mcIdType *conn=_nodal_connec->begin();
5813   const mcIdType *connI=_nodal_connec_index->begin();
5814   mcIdType nbOfCells=getNumberOfCells();
5815   std::vector<INTERP_KERNEL::NormalizedCellType> types;
5816   std::vector<mcIdType> typeRangeVals(1);
5817   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5818     {
5819       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5820       if(std::find(types.begin(),types.end(),curType)!=types.end())
5821         {
5822           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
5823         }
5824       types.push_back(curType);
5825       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5826       typeRangeVals.push_back(ToIdType(std::distance(connI,i)));
5827     }
5828   //
5829   DataArrayIdType *castArr=0,*rankInsideCast=0,*castsPresent=0;
5830   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
5831   MCAuto<DataArrayIdType> tmp0=castArr;
5832   MCAuto<DataArrayIdType> tmp1=rankInsideCast;
5833   MCAuto<DataArrayIdType> tmp2=castsPresent;
5834   //
5835   mcIdType nbOfCastsFinal=castsPresent->getNumberOfTuples();
5836   code.resize(3*nbOfCastsFinal);
5837   std::vector< MCAuto<DataArrayIdType> > idsInPflPerType2;
5838   std::vector< MCAuto<DataArrayIdType> > idsPerType2;
5839   for(mcIdType i=0;i<nbOfCastsFinal;i++)
5840     {
5841       mcIdType castId=castsPresent->getIJ(i,0);
5842       MCAuto<DataArrayIdType> tmp3=castArr->findIdsEqual(castId);
5843       idsInPflPerType2.push_back(tmp3);
5844       code[3*i]=ToIdType(types[castId]);
5845       code[3*i+1]=tmp3->getNumberOfTuples();
5846       MCAuto<DataArrayIdType> tmp4=rankInsideCast->selectByTupleId(tmp3->begin(),tmp3->begin()+tmp3->getNumberOfTuples());
5847       if(!smartPflKiller || !tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
5848         {
5849           tmp4->copyStringInfoFrom(*profile);
5850           idsPerType2.push_back(tmp4);
5851           code[3*i+2]=ToIdType(idsPerType2.size())-1;
5852         }
5853       else
5854         {
5855           code[3*i+2]=-1;
5856         }
5857     }
5858   std::size_t sz2=idsInPflPerType2.size();
5859   idsInPflPerType.resize(sz2);
5860   for(std::size_t i=0;i<sz2;i++)
5861     {
5862       DataArrayIdType *locDa=idsInPflPerType2[i];
5863       locDa->incrRef();
5864       idsInPflPerType[i]=locDa;
5865     }
5866   std::size_t sz=idsPerType2.size();
5867   idsPerType.resize(sz);
5868   for(std::size_t i=0;i<sz;i++)
5869     {
5870       DataArrayIdType *locDa=idsPerType2[i];
5871       locDa->incrRef();
5872       idsPerType[i]=locDa;
5873     }
5874 }
5875
5876 /*!
5877  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
5878  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
5879  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
5880  * 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.
5881  */
5882 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayIdType *desc, DataArrayIdType *descIndx, DataArrayIdType *&revDesc, DataArrayIdType *&revDescIndx, DataArrayIdType *& nM1LevMeshIds, DataArrayIdType *&meshnM1Old2New) const
5883 {
5884   checkFullyDefined();
5885   nM1LevMesh->checkFullyDefined();
5886   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
5887     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
5888   if(_coords!=nM1LevMesh->getCoords())
5889     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
5890   MCAuto<DataArrayIdType> tmp0=DataArrayIdType::New();
5891   MCAuto<DataArrayIdType> tmp1=DataArrayIdType::New();
5892   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
5893   MCAuto<DataArrayIdType> ret0=ret1->sortCellsInMEDFileFrmt();
5894   desc->transformWithIndArr(ret0->begin(),ret0->begin()+ret0->getNbOfElems());
5895   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
5896   tmp->setConnectivity(tmp0,tmp1);
5897   tmp->renumberCells(ret0->begin(),false);
5898   revDesc=tmp->getNodalConnectivity();
5899   revDescIndx=tmp->getNodalConnectivityIndex();
5900   DataArrayIdType *ret=0;
5901   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
5902     {
5903       mcIdType tmp2;
5904       ret->getMaxValue(tmp2);
5905       ret->decrRef();
5906       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
5907       throw INTERP_KERNEL::Exception(oss.str());
5908     }
5909   nM1LevMeshIds=ret;
5910   //
5911   revDesc->incrRef();
5912   revDescIndx->incrRef();
5913   ret1->incrRef();
5914   ret0->incrRef();
5915   meshnM1Old2New=ret0;
5916   return ret1;
5917 }
5918
5919 /*!
5920  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
5921  * necessary for writing the mesh to MED file. Additionally returns a permutation array
5922  * in "Old to New" mode.
5923  *  \return DataArrayIdType * - a new instance of DataArrayIdType. The caller is to delete
5924  *          this array using decrRef() as it is no more needed.
5925  *  \throw If the nodal connectivity of cells is not defined.
5926  */
5927 DataArrayIdType *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
5928 {
5929   checkConnectivityFullyDefined();
5930   MCAuto<DataArrayIdType> ret=getRenumArrForMEDFileFrmt();
5931   renumberCells(ret->begin(),false);
5932   return ret.retn();
5933 }
5934
5935 /*!
5936  * This methods checks that cells are sorted by their types.
5937  * This method makes asumption (no check) that connectivity is correctly set before calling.
5938  */
5939 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
5940 {
5941   checkFullyDefined();
5942   const mcIdType *conn=_nodal_connec->begin();
5943   const mcIdType *connI=_nodal_connec_index->begin();
5944   mcIdType nbOfCells=getNumberOfCells();
5945   std::set<INTERP_KERNEL::NormalizedCellType> types;
5946   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5947     {
5948       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5949       if(types.find(curType)!=types.end())
5950         return false;
5951       types.insert(curType);
5952       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5953     }
5954   return true;
5955 }
5956
5957 /*!
5958  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
5959  * The geometric type order is specified by MED file.
5960  *
5961  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
5962  */
5963 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
5964 {
5965   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
5966 }
5967
5968 /*!
5969  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
5970  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
5971  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
5972  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
5973  */
5974 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
5975 {
5976   checkFullyDefined();
5977   const mcIdType *conn=_nodal_connec->begin();
5978   const mcIdType *connI=_nodal_connec_index->begin();
5979   mcIdType nbOfCells=getNumberOfCells();
5980   if(nbOfCells==0)
5981     return true;
5982   mcIdType lastPos=-1;
5983   std::set<INTERP_KERNEL::NormalizedCellType> sg;
5984   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
5985     {
5986       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
5987       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
5988       if(isTypeExists!=orderEnd)
5989         {
5990           mcIdType pos=ToIdType(std::distance(orderBg,isTypeExists));
5991           if(pos<=lastPos)
5992             return false;
5993           lastPos=pos;
5994           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
5995         }
5996       else
5997         {
5998           if(sg.find(curType)==sg.end())
5999             {
6000               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6001               sg.insert(curType);
6002             }
6003           else
6004             return false;
6005         }
6006     }
6007   return true;
6008 }
6009
6010 /*!
6011  * This method returns 2 newly allocated DataArrayIdType instances. The first is an array of size 'this->getNumberOfCells()' with one component,
6012  * 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
6013  * 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'.
6014  */
6015 DataArrayIdType *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayIdType *&nbPerType) const
6016 {
6017   checkConnectivityFullyDefined();
6018   mcIdType nbOfCells=getNumberOfCells();
6019   const mcIdType *conn=_nodal_connec->begin();
6020   const mcIdType *connI=_nodal_connec_index->begin();
6021   MCAuto<DataArrayIdType> tmpa=DataArrayIdType::New();
6022   MCAuto<DataArrayIdType> tmpb=DataArrayIdType::New();
6023   tmpa->alloc(nbOfCells,1);
6024   tmpb->alloc(std::distance(orderBg,orderEnd),1);
6025   tmpb->fillWithZero();
6026   mcIdType *tmp=tmpa->getPointer();
6027   mcIdType *tmp2=tmpb->getPointer();
6028   for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6029     {
6030       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
6031       if(where!=orderEnd)
6032         {
6033           mcIdType pos=ToIdType(std::distance(orderBg,where));
6034           tmp2[pos]++;
6035           tmp[std::distance(connI,i)]=pos;
6036         }
6037       else
6038         {
6039           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
6040           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
6041           oss << " has a type " << cm.getRepr() << " not in input array of type !";
6042           throw INTERP_KERNEL::Exception(oss.str());
6043         }
6044     }
6045   nbPerType=tmpb.retn();
6046   return tmpa.retn();
6047 }
6048
6049 /*!
6050  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
6051  *
6052  * \return a new object containing the old to new correspondence.
6053  *
6054  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6055  */
6056 DataArrayIdType *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
6057 {
6058   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
6059 }
6060
6061 /*!
6062  * 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.
6063  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
6064  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
6065  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
6066  */
6067 DataArrayIdType *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
6068 {
6069   DataArrayIdType *nbPerType=0;
6070   MCAuto<DataArrayIdType> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
6071   nbPerType->decrRef();
6072   return tmpa->buildPermArrPerLevel();
6073 }
6074
6075 /*!
6076  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
6077  * The number of cells remains unchanged after the call of this method.
6078  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
6079  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
6080  *
6081  * \return the array giving the correspondence old to new.
6082  */
6083 DataArrayIdType *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
6084 {
6085   checkFullyDefined();
6086   computeTypes();
6087   const mcIdType *conn=_nodal_connec->begin();
6088   const mcIdType *connI=_nodal_connec_index->begin();
6089   mcIdType nbOfCells=getNumberOfCells();
6090   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6091   for(const mcIdType *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
6092     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
6093       {
6094         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6095         types.push_back(curType);
6096         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
6097       }
6098   DataArrayIdType *ret=DataArrayIdType::New();
6099   ret->alloc(nbOfCells,1);
6100   mcIdType *retPtr=ret->getPointer();
6101   std::fill(retPtr,retPtr+nbOfCells,-1);
6102   mcIdType newCellId=0;
6103   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6104     {
6105       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6106         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6107           retPtr[std::distance(connI,i)]=newCellId++;
6108     }
6109   renumberCells(retPtr,false);
6110   return ret;
6111 }
6112
6113 /*!
6114  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
6115  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
6116  * This method makes asumption that connectivity is correctly set before calling.
6117  */
6118 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
6119 {
6120   checkConnectivityFullyDefined();
6121   const mcIdType *conn=_nodal_connec->begin();
6122   const mcIdType *connI=_nodal_connec_index->begin();
6123   mcIdType nbOfCells=getNumberOfCells();
6124   std::vector<MEDCouplingUMesh *> ret;
6125   for(const mcIdType *i=connI;i!=connI+nbOfCells;)
6126     {
6127       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
6128       mcIdType beginCellId=ToIdType(std::distance(connI,i));
6129       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,ToIdType(curType)));
6130       mcIdType endCellId=ToIdType(std::distance(connI,i));
6131       mcIdType sz=endCellId-beginCellId;
6132       mcIdType *cells=new mcIdType[sz];
6133       for(mcIdType j=0;j<sz;j++)
6134         cells[j]=beginCellId+j;
6135       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
6136       delete [] cells;
6137       ret.push_back(m);
6138     }
6139   return ret;
6140 }
6141
6142 /*!
6143  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
6144  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
6145  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
6146  *
6147  * \return a newly allocated instance, that the caller must manage.
6148  * \throw If \a this contains more than one geometric type.
6149  * \throw If the nodal connectivity of \a this is not fully defined.
6150  * \throw If the internal data is not coherent.
6151  */
6152 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
6153 {
6154   checkConnectivityFullyDefined();
6155   if(_types.size()!=1)
6156     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6157   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6158   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
6159   ret->setCoords(getCoords());
6160   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6161   if(retC)
6162     {
6163       MCAuto<DataArrayIdType> c=convertNodalConnectivityToStaticGeoTypeMesh();
6164       retC->setNodalConnectivity(c);
6165     }
6166   else
6167     {
6168       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
6169       if(!retD)
6170         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
6171       DataArrayIdType *c=0,*ci=0;
6172       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
6173       MCAuto<DataArrayIdType> cs(c),cis(ci);
6174       retD->setNodalConnectivity(cs,cis);
6175     }
6176   return ret.retn();
6177 }
6178
6179 DataArrayIdType *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
6180 {
6181   checkConnectivityFullyDefined();
6182   if(_types.size()!=1)
6183     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6184   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
6185   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6186   if(cm.isDynamic())
6187     {
6188       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
6189       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
6190       throw INTERP_KERNEL::Exception(oss.str());
6191     }
6192   mcIdType nbCells=getNumberOfCells();
6193   mcIdType typi=ToIdType(typ);
6194   mcIdType nbNodesPerCell=ToIdType(cm.getNumberOfNodes());
6195   MCAuto<DataArrayIdType> connOut=DataArrayIdType::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
6196   mcIdType *outPtr=connOut->getPointer();
6197   const mcIdType *conn=_nodal_connec->begin();
6198   const mcIdType *connI=_nodal_connec_index->begin();
6199   nbNodesPerCell++;
6200   for(mcIdType i=0;i<nbCells;i++,connI++)
6201     {
6202       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
6203         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
6204       else
6205         {
6206           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 << ") !";
6207           throw INTERP_KERNEL::Exception(oss.str());
6208         }
6209     }
6210   return connOut.retn();
6211 }
6212
6213 /*!
6214  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
6215  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
6216  * \param nodalConn
6217  * \param nodalConnI
6218  */
6219 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayIdType *&nodalConn, DataArrayIdType *&nodalConnIndex) const
6220 {
6221   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
6222   checkConnectivityFullyDefined();
6223   if(_types.size()!=1)
6224     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
6225   mcIdType nbCells=getNumberOfCells(),
6226            lgth=_nodal_connec->getNumberOfTuples();
6227   if(lgth<nbCells)
6228     throw INTERP_KERNEL::Exception(msg0);
6229   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),ci(DataArrayIdType::New());
6230   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
6231   mcIdType *cp(c->getPointer()),*cip(ci->getPointer());
6232   const mcIdType *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
6233   cip[0]=0;
6234   for(mcIdType i=0;i<nbCells;i++,cip++,incip++)
6235     {
6236       mcIdType strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
6237       mcIdType delta(stop-strt);
6238       if(delta>=1)
6239         {
6240           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
6241             cp=std::copy(incp+strt,incp+stop,cp);
6242           else
6243             throw INTERP_KERNEL::Exception(msg0);
6244         }
6245       else
6246         throw INTERP_KERNEL::Exception(msg0);
6247       cip[1]=cip[0]+delta;
6248     }
6249   nodalConn=c.retn(); nodalConnIndex=ci.retn();
6250 }
6251
6252 /*!
6253  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
6254  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
6255  * This method is particularly useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
6256  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
6257  * are not used here to avoid the build of big permutation array.
6258  *
6259  * \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
6260  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6261  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayIdType instance whose number of tuples is equal to the number of chunks of same geotype
6262  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
6263  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayIdType instance having the same size than \b szOfCellGrpOfSameType. This
6264  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
6265  * \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
6266  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
6267  */
6268 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
6269                                                                             DataArrayIdType *&szOfCellGrpOfSameType,
6270                                                                             DataArrayIdType *&idInMsOfCellGrpOfSameType)
6271 {
6272   std::vector<const MEDCouplingUMesh *> ms2;
6273   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
6274     if(*it)
6275       {
6276         (*it)->checkConnectivityFullyDefined();
6277         ms2.push_back(*it);
6278       }
6279   if(ms2.empty())
6280     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
6281   const DataArrayDouble *refCoo=ms2[0]->getCoords();
6282   int meshDim=ms2[0]->getMeshDimension();
6283   std::vector<const MEDCouplingUMesh *> m1ssm;
6284   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
6285   //
6286   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
6287   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
6288   mcIdType fake=0,rk=0;
6289   MCAuto<DataArrayIdType> ret1(DataArrayIdType::New()),ret2(DataArrayIdType::New());
6290   ret1->alloc(0,1); ret2->alloc(0,1);
6291   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
6292     {
6293       if(meshDim!=(*it)->getMeshDimension())
6294         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
6295       if(refCoo!=(*it)->getCoords())
6296         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
6297       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
6298       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
6299       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
6300       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
6301         {
6302           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
6303           m1ssmSingleAuto.push_back(singleCell);
6304           m1ssmSingle.push_back(singleCell);
6305           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
6306         }
6307     }
6308   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
6309   MCAuto<DataArrayIdType> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
6310   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
6311   for(mcIdType i=0;i<ToIdType(m1ssm.size());i++)
6312     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
6313   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
6314   szOfCellGrpOfSameType=ret1->renumber(renum->begin());
6315   idInMsOfCellGrpOfSameType=ret2->renumber(renum->begin());
6316   return ret0.retn();
6317 }
6318
6319 /*!
6320  * This method returns a newly created DataArrayIdType instance.
6321  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
6322  */
6323 DataArrayIdType *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const mcIdType *begin, const mcIdType *end) const
6324 {
6325   checkFullyDefined();
6326   const mcIdType *conn=_nodal_connec->begin();
6327   const mcIdType *connIndex=_nodal_connec_index->begin();
6328   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(0,1);
6329   for(const mcIdType *w=begin;w!=end;w++)
6330     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
6331       ret->pushBackSilent(*w);
6332   return ret.retn();
6333 }
6334
6335 /*!
6336  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
6337  * are in [0:getNumberOfCells())
6338  */
6339 DataArrayIdType *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayIdType *da) const
6340 {
6341   checkFullyDefined();
6342   const mcIdType *conn=_nodal_connec->begin();
6343   const mcIdType *connI=_nodal_connec_index->begin();
6344   mcIdType nbOfCells=getNumberOfCells();
6345   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
6346   mcIdType *tmp=new mcIdType[nbOfCells];
6347   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
6348     {
6349       mcIdType j=0;
6350       for(const mcIdType *i=connI;i!=connI+nbOfCells;i++)
6351         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
6352           tmp[std::distance(connI,i)]=j++;
6353     }
6354   DataArrayIdType *ret=DataArrayIdType::New();
6355   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
6356   ret->copyStringInfoFrom(*da);
6357   mcIdType *retPtr=ret->getPointer();
6358   const mcIdType *daPtr=da->begin();
6359   mcIdType nbOfElems=da->getNbOfElems();
6360   for(mcIdType k=0;k<nbOfElems;k++)
6361     retPtr[k]=tmp[daPtr[k]];
6362   delete [] tmp;
6363   return ret;
6364 }
6365
6366 /*!
6367  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
6368  * This method \b works \b for mesh sorted by type.
6369  * cells whose ids is in 'idsPerGeoType' array.
6370  * This method conserves coords and name of mesh.
6371  */
6372 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const mcIdType *idsPerGeoTypeBg, const mcIdType *idsPerGeoTypeEnd) const
6373 {
6374   std::vector<mcIdType> code=getDistributionOfTypes();
6375   std::size_t nOfTypesInThis=code.size()/3;
6376   mcIdType sz=0,szOfType=0;
6377   for(std::size_t i=0;i<nOfTypesInThis;i++)
6378     {
6379       if(code[3*i]!=type)
6380         sz+=code[3*i+1];
6381       else
6382         szOfType=code[3*i+1];
6383     }
6384   for(const mcIdType *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
6385     if(*work<0 || *work>=szOfType)
6386       {
6387         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
6388         oss << ". It should be in [0," << szOfType << ") !";
6389         throw INTERP_KERNEL::Exception(oss.str());
6390       }
6391   MCAuto<DataArrayIdType> idsTokeep=DataArrayIdType::New(); idsTokeep->alloc(sz+std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
6392   mcIdType *idsPtr=idsTokeep->getPointer();
6393   mcIdType offset=0;
6394   for(std::size_t i=0;i<nOfTypesInThis;i++)
6395     {
6396       if(code[3*i]!=type)
6397         for(mcIdType j=0;j<code[3*i+1];j++)
6398           *idsPtr++=offset+j;
6399       else
6400         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6401       offset+=code[3*i+1];
6402     }
6403   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
6404   ret->copyTinyInfoFrom(this);
6405   return ret.retn();
6406 }
6407
6408 /*!
6409  * This method returns a vector of size 'this->getNumberOfCells()'.
6410  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
6411  */
6412 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
6413 {
6414   mcIdType ncell=getNumberOfCells();
6415   std::vector<bool> ret(ncell);
6416   const mcIdType *cI=getNodalConnectivityIndex()->begin();
6417   const mcIdType *c=getNodalConnectivity()->begin();
6418   for(mcIdType i=0;i<ncell;i++)
6419     {
6420       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
6421       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
6422       ret[i]=cm.isQuadratic();
6423     }
6424   return ret;
6425 }
6426
6427 /*!
6428  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
6429  */
6430 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
6431 {
6432   if(other->getType()!=UNSTRUCTURED)
6433     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
6434   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
6435   return MergeUMeshes(this,otherC);
6436 }
6437
6438 /*!
6439  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
6440  * computed by averaging coordinates of cell nodes, so this method is not a right
6441  * choice for degenerated meshes (not well oriented, cells with measure close to zero).
6442  * Beware also that for quadratic meshes, degenerated arc of circles are turned into linear edges for the computation.
6443  * This happens with a default detection precision of eps=1.0e-14. If you need control over this use computeCellCenterOfMassWithPrecision().
6444  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6445  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6446  *          components. The caller is to delete this array using decrRef() as it is
6447  *          no more needed.
6448  *  \throw If the coordinates array is not set.
6449  *  \throw If the nodal connectivity of cells is not defined.
6450  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6451  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6452  */
6453 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
6454 {
6455   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6456   int spaceDim=getSpaceDimension();
6457   mcIdType nbOfCells=getNumberOfCells();
6458   ret->alloc(nbOfCells,spaceDim);
6459   ret->copyStringInfoFrom(*getCoords());
6460   double *ptToFill=ret->getPointer();
6461   const mcIdType *nodal=_nodal_connec->begin();
6462   const mcIdType *nodalI=_nodal_connec_index->begin();
6463   const double *coor=_coords->begin();
6464   for(mcIdType i=0;i<nbOfCells;i++)
6465     {
6466       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6467       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
6468       ptToFill+=spaceDim;
6469     }
6470   return ret.retn();
6471 }
6472
6473
6474 /*!
6475  * See computeCellCenterOfMass().
6476  *  \param eps a precision for the detection of degenerated arc of circles.
6477  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
6478  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
6479  *          components. The caller is to delete this array using decrRef() as it is
6480  *          no more needed.
6481  *  \throw If the coordinates array is not set.
6482  *  \throw If the nodal connectivity of cells is not defined.
6483  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
6484  *  \sa MEDCouplingUMesh::computeCellCenterOfMassWithPrecision
6485  */
6486 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMassWithPrecision(double eps) const
6487 {
6488   INTERP_KERNEL::QuadraticPlanarPrecision prec(eps);
6489   MCAuto<DataArrayDouble> ret = computeCellCenterOfMass();
6490   return ret.retn();
6491 }
6492
6493
6494 /*!
6495  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
6496  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the
6497  *
6498  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned
6499  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
6500  *
6501  * \sa MEDCouplingUMesh::computeCellCenterOfMass
6502  * \throw If \a this is not fully defined (coordinates and connectivity)
6503  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
6504  */
6505 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
6506 {
6507   checkFullyDefined();
6508   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
6509   int spaceDim=getSpaceDimension();
6510   mcIdType nbOfCells=getNumberOfCells();
6511   mcIdType nbOfNodes=getNumberOfNodes();
6512   ret->alloc(nbOfCells,spaceDim);
6513   double *ptToFill=ret->getPointer();
6514   const mcIdType *nodal=_nodal_connec->begin();
6515   const mcIdType *nodalI=_nodal_connec_index->begin();
6516   const double *coor=_coords->begin();
6517   for(mcIdType i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
6518     {
6519       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
6520       std::fill(ptToFill,ptToFill+spaceDim,0.);
6521       if(type!=INTERP_KERNEL::NORM_POLYHED)
6522         {
6523           for(const mcIdType *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
6524             {
6525               if(*conn>=0 && *conn<nbOfNodes)
6526                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
6527               else
6528                 {
6529                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
6530                   throw INTERP_KERNEL::Exception(oss.str());
6531                 }
6532             }
6533           mcIdType nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
6534           if(nbOfNodesInCell>0)
6535             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6536           else
6537             {
6538               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
6539               throw INTERP_KERNEL::Exception(oss.str());
6540             }
6541         }
6542       else
6543         {
6544           std::set<mcIdType> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
6545           s.erase(-1);
6546           for(std::set<mcIdType>::const_iterator it=s.begin();it!=s.end();it++)
6547             {
6548               if(*it>=0 && *it<nbOfNodes)
6549                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
6550               else
6551                 {
6552                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
6553                   throw INTERP_KERNEL::Exception(oss.str());
6554                 }
6555             }
6556           if(!s.empty())
6557             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
6558           else
6559             {
6560               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
6561               throw INTERP_KERNEL::Exception(oss.str());
6562             }
6563         }
6564     }
6565   return ret.retn();
6566 }
6567
6568 /*!
6569  * Returns a new DataArrayDouble holding barycenters of specified cells. The
6570  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
6571  * are specified via an array of cell ids.
6572  *  \warning Validity of the specified cell ids is not checked!
6573  *           Valid range is [ 0, \a this->getNumberOfCells() ).
6574  *  \param [in] begin - an array of cell ids of interest.
6575  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
6576  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
6577  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
6578  *          caller is to delete this array using decrRef() as it is no more needed.
6579  *  \throw If the coordinates array is not set.
6580  *  \throw If the nodal connectivity of cells is not defined.
6581  *
6582  *  \if ENABLE_EXAMPLES
6583  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
6584  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
6585  *  \endif
6586  */
6587 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const mcIdType *begin, const mcIdType *end) const
6588 {
6589   DataArrayDouble *ret=DataArrayDouble::New();
6590   int spaceDim=getSpaceDimension();
6591   std::size_t nbOfTuple=std::distance(begin,end);
6592   ret->alloc(nbOfTuple,spaceDim);
6593   double *ptToFill=ret->getPointer();
6594   double *tmp=new double[spaceDim];
6595   const mcIdType *nodal=_nodal_connec->begin();
6596   const mcIdType *nodalI=_nodal_connec_index->begin();
6597   const double *coor=_coords->begin();
6598   for(const mcIdType *w=begin;w!=end;w++)
6599     {
6600       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
6601       INTERP_KERNEL::computeBarycenter2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
6602       ptToFill+=spaceDim;
6603     }
6604   delete [] tmp;
6605   return ret;
6606 }
6607
6608 /*!
6609  * 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".
6610  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
6611  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
6612  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
6613  * This method is useful to detect 2D cells in 3D space that are not coplanar.
6614  *
6615  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
6616  * \throw If spaceDim!=3 or meshDim!=2.
6617  * \throw If connectivity of \a this is invalid.
6618  * \throw If connectivity of a cell in \a this points to an invalid node.
6619  */
6620 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
6621 {
6622   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
6623   mcIdType nbOfCells=getNumberOfCells();
6624   mcIdType nbOfNodes(getNumberOfNodes());
6625   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
6626     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
6627   ret->alloc(nbOfCells,4);
6628   double *retPtr(ret->getPointer());
6629   const mcIdType *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
6630   const double *coor(_coords->begin());
6631   for(mcIdType i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
6632     {
6633       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
6634       if(nodalI[1]-nodalI[0]>=4)
6635         {
6636           double aa[3]={coor[nodal[nodalI[0]+1+1]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6637                         coor[nodal[nodalI[0]+1+1]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6638                         coor[nodal[nodalI[0]+1+1]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]}
6639           ,bb[3]={coor[nodal[nodalI[0]+1+2]*3+0]-coor[nodal[nodalI[0]+1+0]*3+0],
6640                         coor[nodal[nodalI[0]+1+2]*3+1]-coor[nodal[nodalI[0]+1+0]*3+1],
6641                         coor[nodal[nodalI[0]+1+2]*3+2]-coor[nodal[nodalI[0]+1+0]*3+2]};
6642           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]};
6643           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]));
6644           for(int j=0;j<3;j++)
6645             {
6646               mcIdType nodeId(nodal[nodalI[0]+1+j]);
6647               if(nodeId>=0 && nodeId<nbOfNodes)
6648                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
6649               else
6650                 {
6651                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
6652                   throw INTERP_KERNEL::Exception(oss.str());
6653                 }
6654             }
6655           if(sqrt(cc[0]*cc[0]+cc[1]*cc[1]+cc[2]*cc[2])>(1e-3*aa_norm*bb_norm))
6656             {
6657               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6658               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6659             }
6660           else
6661             {
6662               if(nodalI[1]-nodalI[0]==4)
6663                 {
6664                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : cell" << i << " : Presence of The 3 colinear points !";
6665                   throw INTERP_KERNEL::Exception(oss.str());
6666                 }
6667               //
6668               double dd[3]={0.,0.,0.};
6669               for(mcIdType offset=nodalI[0]+1;offset<nodalI[1];offset++)
6670                 std::transform(coor+3*nodal[offset],coor+3*(nodal[offset]+1),dd,dd,std::plus<double>());
6671               mcIdType nbOfNodesInCell(nodalI[1]-nodalI[0]-1);
6672               std::transform(dd,dd+3,dd,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
6673               std::copy(dd,dd+3,matrix+4*2);
6674               INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
6675               retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
6676             }
6677         }
6678       else
6679         {
6680           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
6681           throw INTERP_KERNEL::Exception(oss.str());
6682         }
6683     }
6684   return ret.retn();
6685 }
6686
6687 /*!
6688  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
6689  *
6690  */
6691 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
6692 {
6693   if(!da)
6694     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
6695   da->checkAllocated();
6696   std::string name(da->getName());
6697   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(name,0));
6698   if(name.empty())
6699     ret->setName("Mesh");
6700   ret->setCoords(da);
6701   mcIdType nbOfTuples(da->getNumberOfTuples());
6702   MCAuto<DataArrayIdType> c(DataArrayIdType::New()),cI(DataArrayIdType::New());
6703   c->alloc(2*nbOfTuples,1);
6704   cI->alloc(nbOfTuples+1,1);
6705   mcIdType *cp(c->getPointer()),*cip(cI->getPointer());
6706   *cip++=0;
6707   for(mcIdType i=0;i<nbOfTuples;i++)
6708     {
6709       *cp++=INTERP_KERNEL::NORM_POINT1;
6710       *cp++=i;
6711       *cip++=2*(i+1);
6712     }
6713   ret->setConnectivity(c,cI,true);
6714   return ret.retn();
6715 }
6716
6717 MCAuto<MEDCouplingUMesh> MEDCouplingUMesh::Build1DMeshFromCoords(DataArrayDouble *da)
6718 {
6719   if(!da)
6720     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build01MeshFromCoords : instance of DataArrayDouble must be not null !");
6721   da->checkAllocated();
6722   std::string name(da->getName());
6723   MCAuto<MEDCouplingUMesh> ret;
6724   {
6725     MCAuto<MEDCouplingCMesh> tmp(MEDCouplingCMesh::New());
6726     MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6727     arr->alloc(da->getNumberOfTuples());
6728     tmp->setCoordsAt(0,arr);
6729     ret=tmp->buildUnstructured();
6730   }
6731   ret->setCoords(da);
6732   if(name.empty())
6733     ret->setName("Mesh");
6734   else
6735     ret->setName(name);
6736   return ret;
6737 }
6738
6739 /*!
6740  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
6741  * Cells and nodes of
6742  * the first mesh precede cells and nodes of the second mesh within the result mesh.
6743  *  \param [in] mesh1 - the first mesh.
6744  *  \param [in] mesh2 - the second mesh.
6745  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6746  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6747  *          is no more needed.
6748  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6749  *  \throw If the coordinates array is not set in none of the meshes.
6750  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6751  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6752  */
6753 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6754 {
6755   std::vector<const MEDCouplingUMesh *> tmp(2);
6756   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
6757   return MergeUMeshes(tmp);
6758 }
6759
6760 /*!
6761  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
6762  * Cells and nodes of
6763  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
6764  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
6765  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6766  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6767  *          is no more needed.
6768  *  \throw If \a a.size() == 0.
6769  *  \throw If \a a[ *i* ] == NULL.
6770  *  \throw If the coordinates array is not set in none of the meshes.
6771  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6772  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6773  */
6774 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const std::vector<const MEDCouplingUMesh *>& a)
6775 {
6776   std::size_t sz=a.size();
6777   if(sz==0)
6778     return MergeUMeshesLL(a);
6779   for(std::size_t ii=0;ii<sz;ii++)
6780     if(!a[ii])
6781       {
6782         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
6783         throw INTERP_KERNEL::Exception(oss.str());
6784       }
6785   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
6786   std::vector< const MEDCouplingUMesh * > aa(sz);
6787   int spaceDim=-3;
6788   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
6789     {
6790       const MEDCouplingUMesh *cur=a[i];
6791       const DataArrayDouble *coo=cur->getCoords();
6792       if(coo)
6793         spaceDim=int(coo->getNumberOfComponents());
6794     }
6795   if(spaceDim==-3)
6796     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
6797   for(std::size_t i=0;i<sz;i++)
6798     {
6799       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
6800       aa[i]=bb[i];
6801     }
6802   return MergeUMeshesLL(aa);
6803 }
6804
6805 /*!
6806  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
6807  * dimension and sharing the node coordinates array.
6808  * All cells of the first mesh precede all cells of the second mesh
6809  * within the result mesh.
6810  *  \param [in] mesh1 - the first mesh.
6811  *  \param [in] mesh2 - the second mesh.
6812  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6813  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6814  *          is no more needed.
6815  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
6816  *  \throw If the meshes do not share the node coordinates array.
6817  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
6818  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
6819  */
6820 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
6821 {
6822   std::vector<const MEDCouplingUMesh *> tmp(2);
6823   tmp[0]=mesh1; tmp[1]=mesh2;
6824   return MergeUMeshesOnSameCoords(tmp);
6825 }
6826
6827 /*!
6828  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6829  * dimension and sharing the node coordinates array.
6830  * All cells of the *i*-th mesh precede all cells of the
6831  * (*i*+1)-th mesh within the result mesh.
6832  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6833  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6834  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6835  *          is no more needed.
6836  *  \throw If \a a.size() == 0.
6837  *  \throw If \a a[ *i* ] == NULL.
6838  *  \throw If the meshes do not share the node coordinates array.
6839  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
6840  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
6841  */
6842 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
6843 {
6844   if(meshes.empty())
6845     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
6846   for(std::size_t ii=0;ii<meshes.size();ii++)
6847     if(!meshes[ii])
6848       {
6849         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
6850         throw INTERP_KERNEL::Exception(oss.str());
6851       }
6852   const DataArrayDouble *coords=meshes.front()->getCoords();
6853   int meshDim=meshes.front()->getMeshDimension();
6854   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
6855   mcIdType meshLgth=0;
6856   mcIdType meshIndexLgth=0;
6857   for(;iter!=meshes.end();iter++)
6858     {
6859       if(coords!=(*iter)->getCoords())
6860         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
6861       if(meshDim!=(*iter)->getMeshDimension())
6862         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
6863       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
6864       meshIndexLgth+=(*iter)->getNumberOfCells();
6865     }
6866   MCAuto<DataArrayIdType> nodal=DataArrayIdType::New();
6867   nodal->alloc(meshLgth,1);
6868   mcIdType *nodalPtr=nodal->getPointer();
6869   MCAuto<DataArrayIdType> nodalIndex=DataArrayIdType::New();
6870   nodalIndex->alloc(meshIndexLgth+1,1);
6871   mcIdType *nodalIndexPtr=nodalIndex->getPointer();
6872   mcIdType offset=0;
6873   for(iter=meshes.begin();iter!=meshes.end();iter++)
6874     {
6875       const mcIdType *nod=(*iter)->getNodalConnectivity()->begin();
6876       const mcIdType *index=(*iter)->getNodalConnectivityIndex()->begin();
6877       mcIdType nbOfCells=(*iter)->getNumberOfCells();
6878       mcIdType meshLgth2=(*iter)->getNodalConnectivityArrayLen();
6879       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
6880       if(iter!=meshes.begin())
6881         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<mcIdType>(),offset));
6882       else
6883         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
6884       offset+=meshLgth2;
6885     }
6886   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
6887   ret->setName("merge");
6888   ret->setMeshDimension(meshDim);
6889   ret->setConnectivity(nodal,nodalIndex,true);
6890   ret->setCoords(coords);
6891   return ret;
6892 }
6893
6894 /*!
6895  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
6896  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
6897  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
6898  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
6899  * New" mode are returned for each input mesh.
6900  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
6901  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
6902  *          valid values [0,1,2], see zipConnectivityTraducer().
6903  *  \param [in,out] corr - an array of DataArrayIdType, of the same size as \a
6904  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
6905  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
6906  *          no more needed.
6907  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
6908  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
6909  *          is no more needed.
6910  *  \throw If \a meshes.size() == 0.
6911  *  \throw If \a meshes[ *i* ] == NULL.
6912  *  \throw If the meshes do not share the node coordinates array.
6913  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
6914  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
6915  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
6916  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
6917  */
6918 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayIdType *>& corr)
6919 {
6920   //All checks are delegated to MergeUMeshesOnSameCoords
6921   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
6922   MCAuto<DataArrayIdType> o2n=ret->zipConnectivityTraducer(compType);
6923   corr.resize(meshes.size());
6924   std::size_t nbOfMeshes=meshes.size();
6925   mcIdType offset=0;
6926   const mcIdType *o2nPtr=o2n->begin();
6927   for(std::size_t i=0;i<nbOfMeshes;i++)
6928     {
6929       DataArrayIdType *tmp=DataArrayIdType::New();
6930       mcIdType curNbOfCells=meshes[i]->getNumberOfCells();
6931       tmp->alloc(curNbOfCells,1);
6932       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
6933       offset+=curNbOfCells;
6934       tmp->setName(meshes[i]->getName());
6935       corr[i]=tmp;
6936     }
6937   return ret.retn();
6938 }
6939
6940 /*!
6941  * Makes all given meshes share the nodal connectivity array. The common connectivity
6942  * array is created by concatenating the connectivity arrays of all given meshes. All
6943  * the given meshes must be of the same space dimension but dimension of cells **can
6944  * differ**. This method is particularly useful in MEDLoader context to build a \ref
6945  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
6946  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
6947  *  \param [in,out] meshes - a vector of meshes to update.
6948  *  \throw If any of \a meshes is NULL.
6949  *  \throw If the coordinates array is not set in any of \a meshes.
6950  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
6951  *  \throw If \a meshes are of different space dimension.
6952  */
6953 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
6954 {
6955   std::size_t sz=meshes.size();
6956   if(sz==0 || sz==1)
6957     return;
6958   std::vector< const DataArrayDouble * > coords(meshes.size());
6959   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
6960   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
6961     {
6962       if((*it))
6963         {
6964           (*it)->checkConnectivityFullyDefined();
6965           const DataArrayDouble *coo=(*it)->getCoords();
6966           if(coo)
6967             *it2=coo;
6968           else
6969             {
6970               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6971               oss << " has no coordinate array defined !";
6972               throw INTERP_KERNEL::Exception(oss.str());
6973             }
6974         }
6975       else
6976         {
6977           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
6978           oss << " is null !";
6979           throw INTERP_KERNEL::Exception(oss.str());
6980         }
6981     }
6982   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
6983   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
6984   mcIdType offset=(*it)->getNumberOfNodes();
6985   (*it++)->setCoords(res);
6986   for(;it!=meshes.end();it++)
6987     {
6988       mcIdType oldNumberOfNodes=(*it)->getNumberOfNodes();
6989       (*it)->setCoords(res);
6990       (*it)->shiftNodeNumbersInConn(offset);
6991       offset+=oldNumberOfNodes;
6992     }
6993 }
6994
6995 /*!
6996  * Merges nodes coincident with a given precision within all given meshes that share
6997  * the nodal connectivity array. The given meshes **can be of different** mesh
6998  * dimension. This method is particularly useful in MEDLoader context to build a \ref
6999  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
7000  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
7001  *  \param [in,out] meshes - a vector of meshes to update.
7002  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
7003  *  \throw If any of \a meshes is NULL.
7004  *  \throw If the \a meshes do not share the same node coordinates array.
7005  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
7006  */
7007 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
7008 {
7009   if(meshes.empty())
7010     return ;
7011   std::set<const DataArrayDouble *> s;
7012   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7013     {
7014       if(*it)
7015         s.insert((*it)->getCoords());
7016       else
7017         {
7018           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 !";
7019           throw INTERP_KERNEL::Exception(oss.str());
7020         }
7021     }
7022   if(s.size()!=1)
7023     {
7024       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 !";
7025       throw INTERP_KERNEL::Exception(oss.str());
7026     }
7027   const DataArrayDouble *coo=*(s.begin());
7028   if(!coo)
7029     return;
7030   //
7031   DataArrayIdType *comm,*commI;
7032   coo->findCommonTuples(eps,-1,comm,commI);
7033   MCAuto<DataArrayIdType> tmp1(comm),tmp2(commI);
7034   mcIdType oldNbOfNodes=coo->getNumberOfTuples();
7035   mcIdType newNbOfNodes;
7036   MCAuto<DataArrayIdType> o2n=DataArrayIdType::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
7037   if(oldNbOfNodes==newNbOfNodes)
7038     return ;
7039   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->begin(),newNbOfNodes);
7040   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
7041     {
7042       (*it)->renumberNodesInConn(o2n->begin());
7043       (*it)->setCoords(newCoords);
7044     }
7045 }
7046
7047
7048 /*!
7049  * This static operates only for coords in 3D. The polygon is specified by its connectivity nodes in [ \a begin , \a end ).
7050  */
7051 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const mcIdType *begin, const mcIdType *end, const double *coords)
7052 {
7053   std::size_t i, ip1;
7054   double v[3]={0.,0.,0.};
7055   std::size_t sz=std::distance(begin,end);
7056   if(!isQuadratic)
7057     for(i=0;i<sz;i++)
7058       {
7059         // Algorithm: sum in v the cross products of (e1, e2) where e_i it the vector between (0,0,0) and point i
7060         // and e2 is linear point directly following e1 in the connectivity. All points are used.
7061         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];
7062         v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
7063         v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
7064       }
7065   else
7066     {
7067       // Same algorithm as above but also using intermediate quadratic points.
7068       // (taking only linear points might lead to issues if the linearized version of the
7069       // polygon is not convex or self-intersecting ... see testCellOrientation4)
7070       std::size_t hsz = sz/2;
7071       for(std::size_t j=0;j<sz;j++)
7072         {
7073           if (j%2)  // current point i is quadratic, next point i+1 is standard
7074             {
7075               i = hsz+(j-1)/2;
7076               ip1 = ((j-1)/2 + 1)%hsz; // ip1 means "i+1", i.e. next point
7077             }
7078           else      // current point i is standard, next point i+1 is quadratic
7079             {
7080               i = j/2;
7081               ip1 = j/2+hsz;
7082             }
7083           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
7084           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
7085           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
7086         }
7087     }
7088   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
7089   return (ret>0.);
7090 }
7091
7092 /*!
7093  * The polyhedron is specified by its connectivity nodes in [ \a begin , \a end ).
7094  */
7095 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7096 {
7097   std::vector<std::pair<mcIdType,mcIdType> > edges;
7098   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7099   const mcIdType *bgFace=begin;
7100   for(std::size_t i=0;i<nbOfFaces;i++)
7101     {
7102       const mcIdType *endFace=std::find(bgFace+1,end,-1);
7103       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7104       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7105         {
7106           std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7107           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
7108             return false;
7109           edges.push_back(p1);
7110         }
7111       bgFace=endFace+1;
7112     }
7113   return INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)>-EPS_FOR_POLYH_ORIENTATION;
7114 }
7115
7116 /*!
7117  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
7118  */
7119 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7120 {
7121   double vec0[3],vec1[3];
7122   std::size_t sz=std::distance(begin,end);
7123   if(sz%2!=0)
7124     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
7125   mcIdType nbOfNodes=ToIdType(sz/2);
7126   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
7127   const double *pt0=coords+3*begin[0];
7128   const double *pt1=coords+3*begin[nbOfNodes];
7129   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
7130   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
7131 }
7132
7133 void MEDCouplingUMesh::CorrectExtrudedStaticCell(mcIdType *begin, mcIdType *end)
7134 {
7135   std::size_t sz=std::distance(begin,end);
7136   INTERP_KERNEL::AutoPtr<mcIdType> tmp=new mcIdType[sz];
7137   std::size_t nbOfNodes(sz/2);
7138   std::copy(begin,end,(mcIdType *)tmp);
7139   for(std::size_t j=1;j<nbOfNodes;j++)
7140     {
7141       begin[j]=tmp[nbOfNodes-j];
7142       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
7143     }
7144 }
7145
7146 bool MEDCouplingUMesh::IsTetra4WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7147 {
7148   std::size_t sz=std::distance(begin,end);
7149   if(sz!=4)
7150     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
7151   double vec0[3],vec1[3];
7152   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
7153   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];
7154   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;
7155 }
7156
7157 bool MEDCouplingUMesh::IsPyra5WellOriented(const mcIdType *begin, const mcIdType *end, const double *coords)
7158 {
7159   std::size_t sz=std::distance(begin,end);
7160   if(sz!=5)
7161     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
7162   double vec0[3];
7163   INTERP_KERNEL::areaVectorOfPolygon<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
7164   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
7165   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
7166 }
7167
7168 /*!
7169  * 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 )
7170  * 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
7171  * a 2D space.
7172  *
7173  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
7174  * \param [in] coords the coordinates with nb of components exactly equal to 3
7175  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
7176  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
7177  * \param [out] res the result is put at the end of the vector without any alteration of the data.
7178  */
7179 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, mcIdType index, DataArrayIdType *res, MEDCouplingUMesh *faces,
7180                                               DataArrayIdType *E_Fi, DataArrayIdType *E_F, DataArrayIdType *F_Ei, DataArrayIdType *F_E)
7181 {
7182   mcIdType nbFaces = E_Fi->getIJ(index + 1, 0) - E_Fi->getIJ(index, 0);
7183   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
7184   double *vPtr=v->getPointer();
7185   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,2);
7186   double *pPtr=p->getPointer();
7187   mcIdType *e_fi = E_Fi->getPointer(), *e_f = E_F->getPointer(), *f_ei = F_Ei->getPointer(), *f_e = F_E->getPointer();
7188   const mcIdType *f_idx = faces->getNodalConnectivityIndex()->getPointer(), *f_cnn = faces->getNodalConnectivity()->getPointer();
7189   for(mcIdType i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
7190     {
7191       mcIdType face = e_f[e_fi[index] + i];
7192       ComputeVecAndPtOfFace(eps, coords->begin(), f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1], vPtr, pPtr);
7193       // to differentiate faces going to different cells:
7194       pPtr++, *pPtr = 0;
7195       for (mcIdType j = f_ei[face]; j < f_ei[face + 1]; j++)
7196         *pPtr += FromIdType<double>(f_e[j]);
7197     }
7198   pPtr=p->getPointer(); vPtr=v->getPointer();
7199   DataArrayIdType *comm1=0,*commI1=0;
7200   v->findCommonTuples(eps,-1,comm1,commI1);
7201   for (mcIdType i = 0; i < nbFaces; i++)
7202     if (comm1->findIdFirstEqual(i) < 0)
7203       {
7204         comm1->pushBackSilent(i);
7205         commI1->pushBackSilent(comm1->getNumberOfTuples());
7206       }
7207   MCAuto<DataArrayIdType> comm1Auto(comm1),commI1Auto(commI1);
7208   const mcIdType *comm1Ptr=comm1->begin();
7209   const mcIdType *commI1Ptr=commI1->begin();
7210   mcIdType nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
7211   res->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYHED));
7212   //
7213   for(mcIdType i=0;i<nbOfGrps1;i++)
7214     {
7215       mcIdType vecId=comm1Ptr[commI1Ptr[i]];
7216       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7217       DataArrayIdType *comm2=0,*commI2=0;
7218       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
7219       for (mcIdType j = 0; j < commI1Ptr[i+1] - commI1Ptr[i]; j++)
7220         if (comm2->findIdFirstEqual(j) < 0)
7221           {
7222             comm2->pushBackSilent(j);
7223             commI2->pushBackSilent(comm2->getNumberOfTuples());
7224           }
7225       MCAuto<DataArrayIdType> comm2Auto(comm2),commI2Auto(commI2);
7226       const mcIdType *comm2Ptr=comm2->begin();
7227       const mcIdType *commI2Ptr=commI2->begin();
7228       mcIdType nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
7229       for(mcIdType j=0;j<nbOfGrps2;j++)
7230         {
7231           if(commI2Ptr[j+1] == commI2Ptr[j] + 1)
7232             {
7233               mcIdType face = e_f[e_fi[index] + comm1Ptr[commI1Ptr[i] + comm2Ptr[commI2Ptr[j]]]]; //hmmm
7234               res->insertAtTheEnd(f_cnn + f_idx[face] + 1, f_cnn + f_idx[face + 1]);
7235               res->pushBackSilent(-1);
7236             }
7237           else
7238             {
7239               mcIdType pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
7240               MCAuto<DataArrayIdType> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
7241               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
7242               ids2->transformWithIndArr(e_f + e_fi[index], e_f + e_fi[index + 1]);
7243               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(faces->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
7244               MCAuto<DataArrayIdType> idsNodeTmp=mm3->zipCoordsTraducer();
7245               MCAuto<DataArrayIdType> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
7246               const mcIdType *idsNodePtr=idsNode->begin();
7247               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];
7248               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
7249               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
7250               if(std::abs(norm)>eps)
7251                 {
7252                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
7253                   mm3->rotate(center,vec,angle);
7254                 }
7255               mm3->changeSpaceDimension(2);
7256               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
7257               const mcIdType *conn4=mm4->getNodalConnectivity()->begin();
7258               const mcIdType *connI4=mm4->getNodalConnectivityIndex()->begin();
7259               mcIdType nbOfCells=mm4->getNumberOfCells();
7260               for(mcIdType k=0;k<nbOfCells;k++)
7261                 {
7262                   int l=0;
7263                   for(const mcIdType *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
7264                     res->pushBackSilent(idsNodePtr[*work]);
7265                   res->pushBackSilent(-1);
7266                 }
7267             }
7268         }
7269     }
7270   res->popBackSilent();
7271 }
7272
7273 /*!
7274  * 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
7275  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
7276  *
7277  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
7278  * \param [in] coords coordinates expected to have 3 components.
7279  * \param [in] begin start of the nodal connectivity of the face.
7280  * \param [in] end end of the nodal connectivity (excluded) of the face.
7281  * \param [out] v the normalized vector of size 3
7282  * \param [out] p the pos of plane
7283  */
7284 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const mcIdType *begin, const mcIdType *end, double *v, double *p)
7285 {
7286   std::size_t nbPoints=std::distance(begin,end);
7287   if(nbPoints<3)
7288     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
7289   double vec[3]={0.,0.,0.};
7290   std::size_t j=0;
7291   bool refFound=false;
7292   for(;j<nbPoints-1 && !refFound;j++)
7293     {
7294       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
7295       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
7296       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
7297       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
7298       if(norm>eps)
7299         {
7300           refFound=true;
7301           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
7302         }
7303     }
7304   for(std::size_t i=j;i<nbPoints-1;i++)
7305     {
7306       double curVec[3];
7307       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
7308       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
7309       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
7310       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
7311       if(norm<eps)
7312         continue;
7313       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
7314       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];
7315       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
7316       if(norm>eps)
7317         {
7318           v[0]/=norm; v[1]/=norm; v[2]/=norm;
7319           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
7320           return ;
7321         }
7322     }
7323   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
7324 }
7325
7326 /*!
7327  * This method tries to obtain a well oriented polyhedron.
7328  * If the algorithm fails, an exception will be thrown.
7329  */
7330 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(mcIdType *begin, mcIdType *end, const double *coords)
7331 {
7332   std::list< std::pair<mcIdType,mcIdType> > edgesOK,edgesFinished;
7333   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
7334   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
7335   isPerm[0]=true;
7336   mcIdType *bgFace=begin,*endFace=std::find(begin+1,end,-1);
7337   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
7338   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<mcIdType,mcIdType> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
7339   //
7340   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
7341     {
7342       bgFace=begin;
7343       std::size_t smthChanged=0;
7344       for(std::size_t i=0;i<nbOfFaces;i++)
7345         {
7346           endFace=std::find(bgFace+1,end,-1);
7347           nbOfEdgesInFace=std::distance(bgFace,endFace);
7348           if(!isPerm[i])
7349             {
7350               bool b;
7351               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7352                 {
7353                   std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7354                   std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7355                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
7356                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
7357                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
7358                 }
7359               if(isPerm[i])
7360                 {
7361                   if(!b)
7362                     std::reverse(bgFace+1,endFace);
7363                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
7364                     {
7365                       std::pair<mcIdType,mcIdType> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
7366                       std::pair<mcIdType,mcIdType> p2(p1.second,p1.first);
7367                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
7368                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7369                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
7370                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str()); }
7371                       std::list< std::pair<mcIdType,mcIdType> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
7372                       if(it!=edgesOK.end())
7373                         {
7374                           edgesOK.erase(it);
7375                           edgesFinished.push_back(p1);
7376                         }
7377                       else
7378                         edgesOK.push_back(p1);
7379                     }
7380                 }
7381             }
7382           bgFace=endFace+1;
7383         }
7384       if(smthChanged==0)
7385         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
7386     }
7387   if(!edgesOK.empty())
7388     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
7389   if(INTERP_KERNEL::calculateVolumeForPolyh2<mcIdType,INTERP_KERNEL::ALL_C_MODE>(begin,ToIdType(std::distance(begin,end)),coords)<-EPS_FOR_POLYH_ORIENTATION)
7390     {//not lucky ! The first face was not correctly oriented : reorient all faces...
7391       bgFace=begin;
7392       for(std::size_t i=0;i<nbOfFaces;i++)
7393         {
7394           endFace=std::find(bgFace+1,end,-1);
7395           std::reverse(bgFace+1,endFace);
7396           bgFace=endFace+1;
7397         }
7398     }
7399 }
7400
7401
7402 /*!
7403  * This method makes the assumption spacedimension == meshdimension == 2.
7404  * This method works only for linear cells.
7405  *
7406  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
7407  */
7408 DataArrayIdType *MEDCouplingUMesh::buildUnionOf2DMesh() const
7409 {
7410   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
7411     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
7412   MCAuto<MEDCouplingUMesh> skin(computeSkin());
7413   mcIdType oldNbOfNodes(skin->getNumberOfNodes());
7414   MCAuto<DataArrayIdType> o2n(skin->zipCoordsTraducer());
7415   mcIdType nbOfNodesExpected(skin->getNumberOfNodes());
7416   MCAuto<DataArrayIdType> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
7417   mcIdType nbCells=skin->getNumberOfCells();
7418   if(nbCells==nbOfNodesExpected)
7419     return buildUnionOf2DMeshLinear(skin,n2o);
7420   else if(2*nbCells==nbOfNodesExpected)
7421     return buildUnionOf2DMeshQuadratic(skin,n2o);
7422   else
7423     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
7424 }
7425
7426 /*!
7427  * This method makes the assumption spacedimension == meshdimension == 3.
7428  * This method works only for linear cells.
7429  *
7430  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
7431  */
7432 DataArrayIdType *MEDCouplingUMesh::buildUnionOf3DMesh() const
7433 {
7434   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
7435     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
7436   MCAuto<MEDCouplingUMesh> m=computeSkin();
7437   const mcIdType *conn=m->getNodalConnectivity()->begin();
7438   const mcIdType *connI=m->getNodalConnectivityIndex()->begin();
7439   mcIdType nbOfCells=m->getNumberOfCells();
7440   MCAuto<DataArrayIdType> ret=DataArrayIdType::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
7441   mcIdType *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
7442   if(nbOfCells<1)
7443     return ret.retn();
7444   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
7445   for(mcIdType i=1;i<nbOfCells;i++)
7446     {
7447       *work++=-1;
7448       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
7449     }
7450   return ret.retn();
7451 }
7452
7453 /*!
7454  * \brief Creates a graph of cell neighbors
7455  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
7456  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
7457  *  For example
7458  *  - index:  0 3 5 6 6
7459  *  - value:  1 2 3 2 3 3
7460  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7461  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
7462  */
7463 MEDCouplingSkyLineArray* MEDCouplingUMesh::generateGraph() const
7464 {
7465   checkConnectivityFullyDefined();
7466
7467   int meshDim = this->getMeshDimension();
7468   MEDCoupling::DataArrayIdType* indexr=MEDCoupling::DataArrayIdType::New();
7469   MEDCoupling::DataArrayIdType* revConn=MEDCoupling::DataArrayIdType::New();
7470   this->getReverseNodalConnectivity(revConn,indexr);
7471   const mcIdType* indexr_ptr=indexr->begin();
7472   const mcIdType* revConn_ptr=revConn->begin();
7473
7474   const MEDCoupling::DataArrayIdType* index;
7475   const MEDCoupling::DataArrayIdType* conn;
7476   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
7477   index=this->getNodalConnectivityIndex();
7478   mcIdType nbCells=this->getNumberOfCells();
7479   const mcIdType* index_ptr=index->begin();
7480   const mcIdType* conn_ptr=conn->begin();
7481
7482   //creating graph arcs (cell to cell relations)
7483   //arcs are stored in terms of (index,value) notation
7484   // 0 3 5 6 6
7485   // 1 2 3 2 3 3
7486   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
7487   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
7488
7489   //warning here one node have less than or equal effective number of cell with it
7490   //but cell could have more than effective nodes
7491   //because other equals nodes in other domain (with other global inode)
7492   std::vector <mcIdType> cell2cell_index(nbCells+1,0);
7493   std::vector <mcIdType> cell2cell;
7494   cell2cell.reserve(3*nbCells);
7495
7496   for (mcIdType icell=0; icell<nbCells;icell++)
7497     {
7498       std::map<mcIdType,mcIdType > counter;
7499       for (mcIdType iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
7500         {
7501           mcIdType inode=conn_ptr[iconn];
7502           for (mcIdType iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
7503             {
7504               mcIdType icell2=revConn_ptr[iconnr];
7505               std::map<mcIdType,mcIdType>::iterator iter=counter.find(icell2);
7506               if (iter!=counter.end()) (iter->second)++;
7507               else counter.insert(std::make_pair(icell2,1));
7508             }
7509         }
7510       for (std::map<mcIdType,mcIdType>::const_iterator iter=counter.begin();
7511            iter!=counter.end(); iter++)
7512         if (iter->second >= meshDim)
7513           {
7514             cell2cell_index[icell+1]++;
7515             cell2cell.push_back(iter->first);
7516           }
7517     }
7518   indexr->decrRef();
7519   revConn->decrRef();
7520   cell2cell_index[0]=0;
7521   for (mcIdType icell=0; icell<nbCells;icell++)
7522     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
7523
7524   //filling up index and value to create skylinearray structure
7525   MEDCouplingSkyLineArray * array(MEDCouplingSkyLineArray::New(cell2cell_index,cell2cell));
7526   return array;
7527 }
7528
7529
7530 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
7531 {
7532   mcIdType nbOfCells=getNumberOfCells();
7533   if(nbOfCells<=0)
7534     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
7535   ofs << "  <" << getVTKDataSetType() << ">\n";
7536   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
7537   ofs << "      <PointData>\n" << pointData << std::endl;
7538   ofs << "      </PointData>\n";
7539   ofs << "      <CellData>\n" << cellData << std::endl;
7540   ofs << "      </CellData>\n";
7541   ofs << "      <Points>\n";
7542   if(getSpaceDimension()==3)
7543     _coords->writeVTK(ofs,8,"Points",byteData);
7544   else
7545     {
7546       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
7547       coo->writeVTK(ofs,8,"Points",byteData);
7548     }
7549   ofs << "      </Points>\n";
7550   ofs << "      <Cells>\n";
7551   const mcIdType *cPtr=_nodal_connec->begin();
7552   const mcIdType *cIPtr=_nodal_connec_index->begin();
7553   MCAuto<DataArrayIdType> faceoffsets=DataArrayIdType::New(); faceoffsets->alloc(nbOfCells,1);
7554   MCAuto<DataArrayIdType> types=DataArrayIdType::New(); types->alloc(nbOfCells,1);
7555   MCAuto<DataArrayIdType> offsets=DataArrayIdType::New(); offsets->alloc(nbOfCells,1);
7556   MCAuto<DataArrayIdType> connectivity=DataArrayIdType::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
7557   mcIdType *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
7558   mcIdType szFaceOffsets=0,szConn=0;
7559   for(mcIdType i=0;i<nbOfCells;i++,w1++,w2++,w3++)
7560     {
7561       *w2=cPtr[cIPtr[i]];
7562       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
7563         {
7564           *w1=-1;
7565           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
7566           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
7567         }
7568       else
7569         {
7570           mcIdType deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
7571           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
7572           std::set<mcIdType> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
7573           *w3=szConn+ToIdType(c.size()); szConn+=ToIdType(c.size());
7574           w4=std::copy(c.begin(),c.end(),w4);
7575         }
7576     }
7577   std::unique_ptr<mcIdType[]> medcoupling2vtkTypeTraducer_mcIdType(new mcIdType[MEDCOUPLING2VTKTYPETRADUCER_LGTH]);
7578   for(auto ii = 0; ii<MEDCOUPLING2VTKTYPETRADUCER_LGTH ; ++ii)
7579     medcoupling2vtkTypeTraducer_mcIdType[ii] = MEDCOUPLING2VTKTYPETRADUCER[ii]!=MEDCOUPLING2VTKTYPETRADUCER_NONE?MEDCOUPLING2VTKTYPETRADUCER[ii] : -1;
7580   types->transformWithIndArr(medcoupling2vtkTypeTraducer_mcIdType.get(),medcoupling2vtkTypeTraducer_mcIdType.get()+MEDCOUPLING2VTKTYPETRADUCER_LGTH);
7581   types->writeVTK(ofs,8,"UInt8","types",byteData);
7582   std::string vtkTypeName = Traits<mcIdType>::VTKReprStr;
7583   offsets->writeVTK(ofs,8,vtkTypeName,"offsets",byteData);
7584   if(szFaceOffsets!=0)
7585     {//presence of Polyhedra
7586       connectivity->reAlloc(szConn);
7587       faceoffsets->writeVTK(ofs,8,vtkTypeName,"faceoffsets",byteData);
7588       MCAuto<DataArrayIdType> faces=DataArrayIdType::New(); faces->alloc(szFaceOffsets,1);
7589       w1=faces->getPointer();
7590       for(mcIdType i=0;i<nbOfCells;i++)
7591         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
7592           {
7593             mcIdType nbFaces=ToIdType(std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1))+1;
7594             *w1++=nbFaces;
7595             const mcIdType *w6=cPtr+cIPtr[i]+1,*w5=0;
7596             for(mcIdType j=0;j<nbFaces;j++)
7597               {
7598                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
7599                 *w1++=ToIdType(std::distance(w6,w5));
7600                 w1=std::copy(w6,w5,w1);
7601                 w6=w5+1;
7602               }
7603           }
7604       faces->writeVTK(ofs,8,vtkTypeName,"faces",byteData);
7605     }
7606   connectivity->writeVTK(ofs,8,vtkTypeName,"connectivity",byteData);
7607   ofs << "      </Cells>\n";
7608   ofs << "    </Piece>\n";
7609   ofs << "  </" << getVTKDataSetType() << ">\n";
7610 }
7611
7612 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
7613 {
7614   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
7615   if(_mesh_dim==-2)
7616     { stream << " Not set !"; return ; }
7617   stream << " Mesh dimension : " << _mesh_dim << ".";
7618   if(_mesh_dim==-1)
7619     return ;
7620   if(!_coords)
7621     { stream << " No coordinates set !"; return ; }
7622   if(!_coords->isAllocated())
7623     { stream << " Coordinates set but not allocated !"; return ; }
7624   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
7625   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
7626   if(!_nodal_connec_index)
7627     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
7628   if(!_nodal_connec_index->isAllocated())
7629     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
7630   mcIdType lgth=_nodal_connec_index->getNumberOfTuples();
7631   std::size_t cpt=_nodal_connec_index->getNumberOfComponents();
7632   if(cpt!=1 || lgth<1)
7633     return ;
7634   stream << std::endl << "Number of cells : " << lgth-1 << ".";
7635 }
7636
7637 std::string MEDCouplingUMesh::getVTKDataSetType() const
7638 {
7639   return std::string("UnstructuredGrid");
7640 }
7641
7642 std::string MEDCouplingUMesh::getVTKFileExtension() const
7643 {
7644   return std::string("vtu");
7645 }
7646
7647
7648
7649 /**
7650  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
7651  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
7652  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
7653  * The caller is to deal with the resulting DataArrayIdType.
7654  *  \throw If the coordinate array is not set.
7655  *  \throw If the nodal connectivity of the cells is not defined.
7656  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
7657  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
7658  *
7659  * \sa DataArrayIdType::sortEachPairToMakeALinkedList
7660  */
7661 DataArrayIdType *MEDCouplingUMesh::orderConsecutiveCells1D() const
7662 {
7663   checkFullyDefined();
7664   if(getMeshDimension()!=1)
7665     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
7666
7667   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
7668   MCAuto<DataArrayIdType> _d(DataArrayIdType::New()),_dI(DataArrayIdType::New());
7669   MCAuto<DataArrayIdType> _rD(DataArrayIdType::New()),_rDI(DataArrayIdType::New());
7670   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
7671   const mcIdType *d(_d->begin()), *dI(_dI->begin());
7672   const mcIdType *rD(_rD->begin()), *rDI(_rDI->begin());
7673   MCAuto<DataArrayIdType> _dsi(_rDI->deltaShiftIndex());
7674   const mcIdType * dsi(_dsi->begin());
7675   MCAuto<DataArrayIdType> dsii = _dsi->findIdsNotInRange(0,3);
7676   m_points=0;
7677   if (dsii->getNumberOfTuples())
7678     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
7679
7680   mcIdType nc=getNumberOfCells();
7681   MCAuto<DataArrayIdType> result(DataArrayIdType::New());
7682   result->alloc(nc,1);
7683
7684   // set of edges not used so far
7685   std::set<mcIdType> edgeSet;
7686   for (mcIdType i=0; i<nc; edgeSet.insert(i), i++);
7687
7688   mcIdType startSeg=0;
7689   mcIdType newIdx=0;
7690   // while we have points with only one neighbor segments
7691   do
7692     {
7693       std::list<mcIdType> linePiece;
7694       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
7695       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
7696         {
7697           // Fill the list forward (resp. backward) from the start segment:
7698           mcIdType activeSeg = startSeg;
7699           mcIdType prevPointId = -20;
7700           mcIdType ptId;
7701           while (!edgeSet.empty())
7702             {
7703               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
7704                 {
7705                   if (direction==0)
7706                     linePiece.push_back(activeSeg);
7707                   else
7708                     linePiece.push_front(activeSeg);
7709                   edgeSet.erase(activeSeg);
7710                 }
7711
7712               mcIdType ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
7713               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
7714               if (dsi[ptId] == 1) // hitting the end of the line
7715                 break;
7716               prevPointId = ptId;
7717               mcIdType seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
7718               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
7719             }
7720         }
7721       // Done, save final piece into DA:
7722       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
7723       newIdx += ToIdType(linePiece.size());
7724
7725       // identify next valid start segment (one which is not consumed)
7726       if(!edgeSet.empty())
7727         startSeg = *(edgeSet.begin());
7728     }
7729   while (!edgeSet.empty());
7730   return result.retn();
7731 }
7732
7733 /**
7734  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
7735  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
7736  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
7737  * a minimal creation of new nodes is wanted.
7738  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
7739  * nodes if a SEG3 is split without information of middle.
7740  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
7741  * avoid to have a non conform mesh.
7742  *
7743  * \return mcIdType - the number of new nodes created (in most of cases 0).
7744  *
7745  * \throw If \a this is not coherent.
7746  * \throw If \a this has not spaceDim equal to 2.
7747  * \throw If \a this has not meshDim equal to 2.
7748  * \throw If some subcells needed to be split are orphan.
7749  * \sa MEDCouplingUMesh::conformize2D
7750  */
7751 mcIdType MEDCouplingUMesh::split2DCells(const DataArrayIdType *desc, const DataArrayIdType *descI, const DataArrayIdType *subNodesInSeg, const DataArrayIdType *subNodesInSegI, const DataArrayIdType *midOpt, const DataArrayIdType *midOptI)
7752 {
7753   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
7754     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
7755   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
7756   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
7757     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
7758   if(midOpt==0 && midOptI==0)
7759     {
7760       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
7761       return 0;
7762     }
7763   else if(midOpt!=0 && midOptI!=0)
7764     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
7765   else
7766     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
7767 }
7768
7769 /*!
7770  * 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
7771  * 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
7772  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
7773  * 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
7774  * 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.
7775  *
7776  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
7777  */
7778 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const mcIdType *nodalConnBg, const mcIdType *nodalConnEnd, DataArrayIdType *nodalConnecOut)
7779 {
7780   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
7781   if(sz>=4)
7782     {
7783       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
7784       if(cm.getDimension()==2)
7785         {
7786           const mcIdType *node=nodalConnBg+1;
7787           mcIdType startNode=*node++;
7788           double refX=coords[2*startNode];
7789           for(;node!=nodalConnEnd;node++)
7790             {
7791               if(coords[2*(*node)]<refX)
7792                 {
7793                   startNode=*node;
7794                   refX=coords[2*startNode];
7795                 }
7796             }
7797           std::vector<mcIdType> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
7798           refX=1e300;
7799           double tmp1;
7800           double tmp2[2];
7801           double angle0=-M_PI/2;
7802           //
7803           mcIdType nextNode=-1;
7804           mcIdType prevNode=-1;
7805           double resRef;
7806           double angleNext=0.;
7807           while(nextNode!=startNode)
7808             {
7809               nextNode=-1;
7810               resRef=1e300;
7811               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
7812                 {
7813                   if(*node!=tmpOut.back() && *node!=prevNode)
7814                     {
7815                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
7816                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
7817                       double res;
7818                       if(angleM<=angle0)
7819                         res=angle0-angleM;
7820                       else
7821                         res=angle0-angleM+2.*M_PI;
7822                       if(res<resRef)
7823                         {
7824                           nextNode=*node;
7825                           resRef=res;
7826                           angleNext=angleM;
7827                         }
7828                     }
7829                 }
7830               if(nextNode!=startNode)
7831                 {
7832                   angle0=angleNext-M_PI;
7833                   if(angle0<-M_PI)
7834                     angle0+=2*M_PI;
7835                   prevNode=tmpOut.back();
7836                   tmpOut.push_back(nextNode);
7837                 }
7838             }
7839           std::vector<mcIdType> tmp3(2*(sz-1));
7840           std::vector<mcIdType>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
7841           std::copy(nodalConnBg+1,nodalConnEnd,it);
7842           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
7843             {
7844               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7845               return false;
7846             }
7847           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
7848             {
7849               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
7850               return false;
7851             }
7852           else
7853             {
7854               nodalConnecOut->pushBackSilent(ToIdType(INTERP_KERNEL::NORM_POLYGON));
7855               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
7856               return true;
7857             }
7858         }
7859       else
7860         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7861     }
7862   else
7863     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
7864 }
7865
7866 /*!
7867  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7868  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7869  * 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]].
7870  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7871  * A negative value in \b arrIn means that it is ignored.
7872  * 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.
7873  *
7874  * \param [in] arrIn arr origin array from which the extraction will be done.
7875  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7876  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7877  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
7878  */
7879 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7880 {
7881   mcIdType seed=0,nbOfDepthPeelingPerformed=0;
7882   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
7883 }
7884
7885 /*!
7886  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
7887  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
7888  * 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]].
7889  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
7890  * A negative value in \b arrIn means that it is ignored.
7891  * 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.
7892  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
7893  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
7894  * \param [in] arrIn arr origin array from which the extraction will be done.
7895  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
7896  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
7897  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
7898  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
7899  * \sa MEDCouplingUMesh::partitionBySpreadZone
7900  */
7901 DataArrayIdType *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const mcIdType *seedBg, const mcIdType *seedEnd, const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn, mcIdType nbOfDepthPeeling, mcIdType& nbOfDepthPeelingPerformed)
7902 {
7903   nbOfDepthPeelingPerformed=0;
7904   if(!arrIndxIn)
7905     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
7906   mcIdType nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
7907   if(nbOfTuples<=0)
7908     {
7909       DataArrayIdType *ret=DataArrayIdType::New(); ret->alloc(0,1);
7910       return ret;
7911     }
7912   //
7913   std::vector<bool> fetched(nbOfTuples,false);
7914   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
7915 }
7916
7917
7918
7919 /*!
7920  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
7921  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
7922  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
7923  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
7924  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
7925  *
7926  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
7927  */
7928 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
7929 {
7930   checkFullyDefined();
7931   int mdim=getMeshDimension();
7932   int spaceDim=getSpaceDimension();
7933   if(mdim!=spaceDim)
7934     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
7935   std::vector<DataArrayIdType *> partition=partitionBySpreadZone();
7936   std::vector< MCAuto<DataArrayIdType> > partitionAuto; partitionAuto.reserve(partition.size());
7937   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayIdType> > >(partitionAuto));
7938   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
7939   ret->setCoords(getCoords());
7940   ret->allocateCells(ToIdType(partition.size()));
7941   //
7942   for(std::vector<DataArrayIdType *>::const_iterator it=partition.begin();it!=partition.end();it++)
7943     {
7944       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
7945       MCAuto<DataArrayIdType> cell;
7946       switch(mdim)
7947       {
7948         case 2:
7949           cell=tmp->buildUnionOf2DMesh();
7950           break;
7951         case 3:
7952           cell=tmp->buildUnionOf3DMesh();
7953           break;
7954         default:
7955           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
7956       }
7957
7958       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->begin()+1);
7959     }
7960   //
7961   ret->finishInsertingCells();
7962   return ret.retn();
7963 }
7964
7965 /*!
7966  * This method partitions \b this into contiguous zone.
7967  * This method only needs a well defined connectivity. Coordinates are not considered here.
7968  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
7969  */
7970 std::vector<DataArrayIdType *> MEDCouplingUMesh::partitionBySpreadZone() const
7971 {
7972   DataArrayIdType *neigh=0,*neighI=0;
7973   computeNeighborsOfCells(neigh,neighI);
7974   MCAuto<DataArrayIdType> neighAuto(neigh),neighIAuto(neighI);
7975   return PartitionBySpreadZone(neighAuto,neighIAuto);
7976 }
7977
7978 std::vector<DataArrayIdType *> MEDCouplingUMesh::PartitionBySpreadZone(const DataArrayIdType *arrIn, const DataArrayIdType *arrIndxIn)
7979 {
7980   if(!arrIn || !arrIndxIn)
7981     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : null input pointers !");
7982   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
7983   mcIdType nbOfTuples(arrIndxIn->getNumberOfTuples());
7984   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1 || nbOfTuples<1)
7985     throw INTERP_KERNEL::Exception("PartitionBySpreadZone : invalid arrays in input !");
7986   mcIdType nbOfCellsCur(nbOfTuples-1);
7987   std::vector<DataArrayIdType *> ret;
7988   if(nbOfCellsCur<=0)
7989     return ret;
7990   std::vector<bool> fetchedCells(nbOfCellsCur,false);
7991   std::vector< MCAuto<DataArrayIdType> > ret2;
7992   mcIdType seed=0;
7993   while(seed<nbOfCellsCur)
7994     {
7995       mcIdType nbOfPeelPerformed=0;
7996       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfPeelPerformed));
7997       seed=ToIdType(std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false)));
7998     }
7999   for(std::vector< MCAuto<DataArrayIdType> >::iterator it=ret2.begin();it!=ret2.end();it++)
8000     ret.push_back((*it).retn());
8001   return ret;
8002 }
8003
8004 /*!
8005  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
8006  * newly allocated DataArrayIdType instance with 2 components ready to be interpreted as input of DataArrayIdType::findRangeIdForEachTuple method.
8007  *
8008  * \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.
8009  * \return a newly allocated DataArrayIdType to be managed by the caller.
8010  * \throw In case of \a code has not the right format (typically of size 3*n)
8011  */
8012 DataArrayIdType *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<mcIdType>& code)
8013 {
8014   MCAuto<DataArrayIdType> ret=DataArrayIdType::New();
8015   std::size_t nb=code.size()/3;
8016   if(code.size()%3!=0)
8017     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
8018   ret->alloc(nb,2);
8019   mcIdType *retPtr=ret->getPointer();
8020   for(std::size_t i=0;i<nb;i++,retPtr+=2)
8021     {
8022       retPtr[0]=code[3*i+2];
8023       retPtr[1]=code[3*i+2]+code[3*i+1];
8024     }
8025   return ret.retn();
8026 }
8027
8028 /*!
8029  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
8030  * All cells in \a this are expected to be linear 3D cells.
8031  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
8032  * It leads to an increase to number of cells.
8033  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
8034  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints
8035  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
8036  *
8037  * \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.
8038  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
8039  * \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.
8040  * \param [out] n2oCells - A new instance of DataArrayIdType holding, for each new cell,
8041  *          an id of old cell producing it. The caller is to delete this array using
8042  *         decrRef() as it is no more needed.
8043  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
8044  *
8045  * \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
8046  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
8047  *
8048  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
8049  * \throw If \a this is not fully constituted with linear 3D cells.
8050  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
8051  */
8052 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayIdType *& n2oCells, mcIdType& nbOfAdditionalPoints) const
8053 {
8054   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
8055   checkConnectivityFullyDefined();
8056   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8057     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
8058   mcIdType nbOfCells=getNumberOfCells();
8059   mcIdType nbNodes(getNumberOfNodes());
8060   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
8061   MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbOfCells,1);
8062   mcIdType *retPt(ret->getPointer());
8063   MCAuto<DataArrayIdType> newConn(DataArrayIdType::New()); newConn->alloc(0,1);
8064   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
8065   const mcIdType *oldc(_nodal_connec->begin());
8066   const mcIdType *oldci(_nodal_connec_index->begin());
8067   const double *coords(_coords->begin());
8068   for(mcIdType i=0;i<nbOfCells;i++,oldci++,retPt++)
8069     {
8070       std::vector<mcIdType> a; std::vector<double> b;
8071       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
8072       std::size_t nbOfTet(a.size()/4); *retPt=ToIdType(nbOfTet);
8073       const mcIdType *aa(&a[0]);
8074       if(!b.empty())
8075         {
8076           for(std::vector<mcIdType>::iterator it=a.begin();it!=a.end();it++)
8077             if(*it<0)
8078               *it=(-(*(it))-1+nbNodes);
8079           addPts->insertAtTheEnd(b.begin(),b.end());
8080           nbNodes+=ToIdType(b.size()/3);
8081         }
8082       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
8083         newConn->insertAtTheEnd(aa,aa+4);
8084     }
8085   if(!addPts->empty())
8086     {
8087       addPts->rearrange(3);
8088       nbOfAdditionalPoints=addPts->getNumberOfTuples();
8089       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
8090       ret0->setCoords(addPts);
8091     }
8092   else
8093     {
8094       nbOfAdditionalPoints=0;
8095       ret0->setCoords(getCoords());
8096     }
8097   ret0->setNodalConnectivity(newConn);
8098   //
8099   ret->computeOffsetsFull();
8100   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
8101   return ret0.retn();
8102 }
8103
8104 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
8105     _own_cell(true),_cell_id(-1),_nb_cell(0)
8106 {
8107   if(mesh)
8108     {
8109       mesh->incrRef();
8110       _nb_cell=mesh->getNumberOfCells();
8111     }
8112 }
8113
8114 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
8115 {
8116   if(_mesh)
8117     _mesh->decrRef();
8118   if(_own_cell)
8119     delete _cell;
8120 }
8121
8122 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_cell(itc),
8123     _own_cell(false),_cell_id(bg-1),
8124     _nb_cell(end)
8125 {
8126   if(mesh)
8127     mesh->incrRef();
8128 }
8129
8130 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
8131 {
8132   _cell_id++;
8133   if(_cell_id<_nb_cell)
8134     {
8135       _cell->next();
8136       return _cell;
8137     }
8138   else
8139     return 0;
8140 }
8141
8142 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
8143 {
8144   if(_mesh)
8145     _mesh->incrRef();
8146 }
8147
8148 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
8149 {
8150   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
8151 }
8152
8153 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
8154 {
8155   if(_mesh)
8156     _mesh->decrRef();
8157 }
8158
8159 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, mcIdType bg, mcIdType end):_mesh(mesh),_type(type),
8160     _itc(itc),
8161     _bg(bg),_end(end)
8162 {
8163   if(_mesh)
8164     _mesh->incrRef();
8165 }
8166
8167 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
8168 {
8169   if(_mesh)
8170     _mesh->decrRef();
8171 }
8172
8173 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
8174 {
8175   return _type;
8176 }
8177
8178 mcIdType MEDCouplingUMeshCellEntry::getNumberOfElems() const
8179 {
8180   return _end-_bg;
8181 }
8182
8183 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
8184 {
8185   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
8186 }
8187
8188 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
8189 {
8190   if(mesh)
8191     {
8192       mesh->incrRef();
8193       _nb_cell=mesh->getNumberOfCells();
8194     }
8195 }
8196
8197 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
8198 {
8199   if(_mesh)
8200     _mesh->decrRef();
8201   delete _cell;
8202 }
8203
8204 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
8205 {
8206   const mcIdType *c=_mesh->getNodalConnectivity()->begin();
8207   const mcIdType *ci=_mesh->getNodalConnectivityIndex()->begin();
8208   if(_cell_id<_nb_cell)
8209     {
8210       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
8211       mcIdType nbOfElems=ToIdType(std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type))));
8212       mcIdType startId=_cell_id;
8213       _cell_id+=nbOfElems;
8214       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
8215     }
8216   else
8217     return 0;
8218 }
8219
8220 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
8221 {
8222   if(mesh)
8223     {
8224       _conn=mesh->getNodalConnectivity()->getPointer();
8225       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
8226     }
8227 }
8228
8229 void MEDCouplingUMeshCell::next()
8230 {
8231   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8232     {
8233       _conn+=_conn_lgth;
8234       _conn_indx++;
8235     }
8236   _conn_lgth=_conn_indx[1]-_conn_indx[0];
8237 }
8238
8239 std::string MEDCouplingUMeshCell::repr() const
8240 {
8241   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8242     {
8243       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
8244       oss << " : ";
8245       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<mcIdType>(oss," "));
8246       return oss.str();
8247     }
8248   else
8249     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
8250 }
8251
8252 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
8253 {
8254   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8255     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
8256   else
8257     return INTERP_KERNEL::NORM_ERROR;
8258 }
8259
8260 const mcIdType *MEDCouplingUMeshCell::getAllConn(mcIdType& lgth) const
8261 {
8262   lgth=_conn_lgth;
8263   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
8264     return _conn;
8265   else
8266     return 0;
8267 }