Salome HOME
Merge branch 'master' of ssh://git.salome-platform.org/tools/medcoupling
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingUMesh.cxx
1 // Copyright (C) 2007-2016  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 (CEA/DEN)
20
21 #include "MEDCouplingUMesh.hxx"
22 #include "MEDCoupling1GTUMesh.hxx"
23 #include "MEDCouplingMemArray.txx"
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
45 #include <sstream>
46 #include <fstream>
47 #include <numeric>
48 #include <cstring>
49 #include <limits>
50 #include <list>
51
52 using namespace MEDCoupling;
53
54 double MEDCouplingUMesh::EPS_FOR_POLYH_ORIENTATION=1.e-14;
55
56 /// @cond INTERNAL
57 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_HEXA20, INTERP_KERNEL::NORM_HEXA27, INTERP_KERNEL::NORM_POLYHED };
58 /// @endcond
59
60 MEDCouplingUMesh *MEDCouplingUMesh::New()
61 {
62   return new MEDCouplingUMesh;
63 }
64
65 MEDCouplingUMesh *MEDCouplingUMesh::New(const std::string& meshName, int meshDim)
66 {
67   MEDCouplingUMesh *ret=new MEDCouplingUMesh;
68   ret->setName(meshName);
69   ret->setMeshDimension(meshDim);
70   return ret;
71 }
72
73 /*!
74  * Returns a new MEDCouplingUMesh which is a full copy of \a this one. No data is shared
75  * between \a this and the new mesh.
76  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
77  *          delete this mesh using decrRef() as it is no more needed. 
78  */
79 MEDCouplingUMesh *MEDCouplingUMesh::deepCopy() const
80 {
81   return clone(true);
82 }
83
84
85 /*!
86  * Returns a new MEDCouplingUMesh which is a copy of \a this one.
87  *  \param [in] recDeepCpy - if \a true, the copy is deep, else all data arrays of \a
88  * this mesh are shared by the new mesh.
89  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingMesh. The caller is to
90  *          delete this mesh using decrRef() as it is no more needed. 
91  */
92 MEDCouplingUMesh *MEDCouplingUMesh::clone(bool recDeepCpy) const
93 {
94   return new MEDCouplingUMesh(*this,recDeepCpy);
95 }
96
97 /*!
98  * This method behaves mostly like MEDCouplingUMesh::deepCopy method, except that only nodal connectivity arrays are deeply copied.
99  * The coordinates are shared between \a this and the returned instance.
100  * 
101  * \return MEDCouplingUMesh * - A new object instance holding the copy of \a this (deep for connectivity, shallow for coordiantes)
102  * \sa MEDCouplingUMesh::deepCopy
103  */
104 MEDCouplingUMesh *MEDCouplingUMesh::deepCopyConnectivityOnly() const
105 {
106   checkConnectivityFullyDefined();
107   MCAuto<MEDCouplingUMesh> ret=clone(false);
108   MCAuto<DataArrayInt> c(getNodalConnectivity()->deepCopy()),ci(getNodalConnectivityIndex()->deepCopy());
109   ret->setConnectivity(c,ci);
110   return ret.retn();
111 }
112
113 void MEDCouplingUMesh::shallowCopyConnectivityFrom(const MEDCouplingPointSet *other)
114 {
115   if(!other)
116     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is null !");
117   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
118   if(!otherC)
119     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::shallowCopyConnectivityFrom : input pointer is not an MEDCouplingUMesh instance !");
120   MEDCouplingUMesh *otherC2=const_cast<MEDCouplingUMesh *>(otherC);//sorry :(
121   setConnectivity(otherC2->getNodalConnectivity(),otherC2->getNodalConnectivityIndex(),true);
122 }
123
124 std::size_t MEDCouplingUMesh::getHeapMemorySizeWithoutChildren() const
125 {
126   std::size_t ret(MEDCouplingPointSet::getHeapMemorySizeWithoutChildren());
127   return ret;
128 }
129
130 std::vector<const BigMemoryObject *> MEDCouplingUMesh::getDirectChildrenWithNull() const
131 {
132   std::vector<const BigMemoryObject *> ret(MEDCouplingPointSet::getDirectChildrenWithNull());
133   ret.push_back(_nodal_connec);
134   ret.push_back(_nodal_connec_index);
135   return ret;
136 }
137
138 void MEDCouplingUMesh::updateTime() const
139 {
140   MEDCouplingPointSet::updateTime();
141   if(_nodal_connec)
142     {
143       updateTimeWith(*_nodal_connec);
144     }
145   if(_nodal_connec_index)
146     {
147       updateTimeWith(*_nodal_connec_index);
148     }
149 }
150
151 MEDCouplingUMesh::MEDCouplingUMesh():_mesh_dim(-2),_nodal_connec(0),_nodal_connec_index(0)
152 {
153 }
154
155 /*!
156  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
157  * then \a this mesh is most probably is writable, exchangeable and available for most
158  * of algorithms. When a mesh is constructed from scratch, it is a good habit to call
159  * this method to check that all is in order with \a this mesh.
160  *  \throw If the mesh dimension is not set.
161  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
162  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
163  *  \throw If the connectivity data array has more than one component.
164  *  \throw If the connectivity data array has a named component.
165  *  \throw If the connectivity index data array has more than one component.
166  *  \throw If the connectivity index data array has a named component.
167  */
168 void MEDCouplingUMesh::checkConsistencyLight() const
169 {
170   if(_mesh_dim<-1)
171     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
172   if(_mesh_dim!=-1)
173     MEDCouplingPointSet::checkConsistencyLight();
174   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
175     {
176       if((int)INTERP_KERNEL::CellModel::GetCellModel(*iter).getDimension()!=_mesh_dim)
177         {
178           std::ostringstream message;
179           message << "Mesh invalid because dimension is " << _mesh_dim << " and there is presence of cell(s) with type " << (*iter);
180           throw INTERP_KERNEL::Exception(message.str().c_str());
181         }
182     }
183   if(_nodal_connec)
184     {
185       if(_nodal_connec->getNumberOfComponents()!=1)
186         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to be with number of components set to one !");
187       if(_nodal_connec->getInfoOnComponent(0)!="")
188         throw INTERP_KERNEL::Exception("Nodal connectivity array is expected to have no info on its single component !");
189     }
190   else
191     if(_mesh_dim!=-1)
192       throw INTERP_KERNEL::Exception("Nodal connectivity array is not defined !");
193   if(_nodal_connec_index)
194     {
195       if(_nodal_connec_index->getNumberOfComponents()!=1)
196         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to be with number of components set to one !");
197       if(_nodal_connec_index->getInfoOnComponent(0)!="")
198         throw INTERP_KERNEL::Exception("Nodal connectivity index array is expected to have no info on its single component !");
199     }
200   else
201     if(_mesh_dim!=-1)
202       throw INTERP_KERNEL::Exception("Nodal connectivity index array is not defined !");
203 }
204
205 /*!
206  * Checks if \a this mesh is well defined. If no exception is thrown by this method,
207  * then \a this mesh is most probably is writable, exchangeable and available for all
208  * algorithms. <br> In addition to the checks performed by checkConsistencyLight(), this
209  * method thoroughly checks the nodal connectivity.
210  *  \param [in] eps - a not used parameter.
211  *  \throw If the mesh dimension is not set.
212  *  \throw If the coordinates array is not set (if mesh dimension != -1 ).
213  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
214  *  \throw If the connectivity data array has more than one component.
215  *  \throw If the connectivity data array has a named component.
216  *  \throw If the connectivity index data array has more than one component.
217  *  \throw If the connectivity index data array has a named component.
218  *  \throw If number of nodes defining an element does not correspond to the type of element.
219  *  \throw If the nodal connectivity includes an invalid node id.
220  */
221 void MEDCouplingUMesh::checkConsistency(double eps) const
222 {
223   checkConsistencyLight();
224   if(_mesh_dim==-1)
225     return ;
226   int meshDim=getMeshDimension();
227   int nbOfNodes=getNumberOfNodes();
228   int nbOfCells=getNumberOfCells();
229   const int *ptr=_nodal_connec->getConstPointer();
230   const int *ptrI=_nodal_connec_index->getConstPointer();
231   for(int i=0;i<nbOfCells;i++)
232     {
233       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)ptr[ptrI[i]]);
234       if((int)cm.getDimension()!=meshDim)
235         {
236           std::ostringstream oss;
237           oss << "MEDCouplingUMesh::checkConsistency : cell << #" << i<< " with type Type " << cm.getRepr() << " in 'this' whereas meshdim == " << meshDim << " !";
238           throw INTERP_KERNEL::Exception(oss.str().c_str());
239         }
240       int nbOfNodesInCell=ptrI[i+1]-ptrI[i]-1;
241       if(!cm.isDynamic())
242         if(nbOfNodesInCell!=(int)cm.getNumberOfNodes())
243           {
244             std::ostringstream oss;
245             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with static Type '" << cm.getRepr() << "' has " <<  cm.getNumberOfNodes();
246             oss << " nodes whereas in connectivity there is " << nbOfNodesInCell << " nodes ! Looks very bad !";
247             throw INTERP_KERNEL::Exception(oss.str().c_str());
248           }
249       if(cm.isQuadratic() && cm.isDynamic() && meshDim == 2)
250         if (nbOfNodesInCell % 2 || nbOfNodesInCell < 4)
251           {
252             std::ostringstream oss;
253             oss << "MEDCouplingUMesh::checkConsistency : cell #" << i << " with quadratic type '" << cm.getRepr() << "' has " <<  nbOfNodesInCell;
254             oss << " nodes. This should be even, and greater or equal than 4!! Looks very bad!";
255             throw INTERP_KERNEL::Exception(oss.str().c_str());
256           }
257       for(const int *w=ptr+ptrI[i]+1;w!=ptr+ptrI[i+1];w++)
258         {
259           int nodeId=*w;
260           if(nodeId>=0)
261             {
262               if(nodeId>=nbOfNodes)
263                 {
264                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " whereas there are only " << nbOfNodes << " nodes in the mesh !";
265                   throw INTERP_KERNEL::Exception(oss.str().c_str());
266                 }
267             }
268           else if(nodeId<-1)
269             {
270               std::ostringstream oss; oss << "Cell #" << i << " is built with node #" << nodeId << " in connectivity ! sounds bad !";
271               throw INTERP_KERNEL::Exception(oss.str().c_str());
272             }
273           else
274             {
275               if((INTERP_KERNEL::NormalizedCellType)(ptr[ptrI[i]])!=INTERP_KERNEL::NORM_POLYHED)
276                 {
277                   std::ostringstream oss; oss << "Cell #" << i << " is built with node #-1 in connectivity ! sounds bad !";
278                   throw INTERP_KERNEL::Exception(oss.str().c_str());
279                 }
280             }
281         }
282     }
283 }
284
285 /*!
286  * Sets dimension of \a this mesh. The mesh dimension in general depends on types of
287  * elements contained in the mesh. For more info on the mesh dimension see
288  * \ref MEDCouplingUMeshPage.
289  *  \param [in] meshDim - a new mesh dimension.
290  *  \throw If \a meshDim is invalid. A valid range is <em> -1 <= meshDim <= 3</em>.
291  */
292 void MEDCouplingUMesh::setMeshDimension(int meshDim)
293 {
294   if(meshDim<-1 || meshDim>3)
295     throw INTERP_KERNEL::Exception("Invalid meshDim specified ! Must be greater or equal to -1 and lower or equal to 3 !");
296   _mesh_dim=meshDim;
297   declareAsNew();
298 }
299
300 /*!
301  * Allocates memory to store an estimation of the given number of cells. The closer is the estimation to the number of cells effectively inserted,
302  * the less will the library need to reallocate memory. If the number of cells to be inserted is not known simply put 0 to this parameter.
303  * If a nodal connectivity previouly existed before the call of this method, it will be reset.
304  *
305  *  \param [in] nbOfCells - estimation of the number of cell \a this mesh will contain.
306  *
307  *  \if ENABLE_EXAMPLES
308  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
309  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
310  *  \endif
311  */
312 void MEDCouplingUMesh::allocateCells(int nbOfCells)
313 {
314   if(nbOfCells<0)
315     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::allocateCells : the input number of cells should be >= 0 !");
316   if(_nodal_connec_index)
317     {
318       _nodal_connec_index->decrRef();
319     }
320   if(_nodal_connec)
321     {
322       _nodal_connec->decrRef();
323     }
324   _nodal_connec_index=DataArrayInt::New();
325   _nodal_connec_index->reserve(nbOfCells+1);
326   _nodal_connec_index->pushBackSilent(0);
327   _nodal_connec=DataArrayInt::New();
328   _nodal_connec->reserve(2*nbOfCells);
329   _types.clear();
330   declareAsNew();
331 }
332
333 /*!
334  * Appends a cell to the connectivity array. For deeper understanding what is
335  * happening see \ref MEDCouplingUMeshNodalConnectivity.
336  *  \param [in] type - type of cell to add.
337  *  \param [in] size - number of nodes constituting this cell.
338  *  \param [in] nodalConnOfCell - the connectivity of the cell to add.
339  * 
340  *  \if ENABLE_EXAMPLES
341  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
342  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
343  *  \endif
344  */
345 void MEDCouplingUMesh::insertNextCell(INTERP_KERNEL::NormalizedCellType type, int size, const int *nodalConnOfCell)
346 {
347   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
348   if(_nodal_connec_index==0)
349     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::insertNextCell : nodal connectivity not set ! invoke allocateCells before calling insertNextCell !");
350   if((int)cm.getDimension()==_mesh_dim)
351     {
352       if(!cm.isDynamic())
353         if(size!=(int)cm.getNumberOfNodes())
354           {
355             std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : Trying to push a " << cm.getRepr() << " cell with a size of " << size;
356             oss << " ! Expecting " << cm.getNumberOfNodes() << " !";
357             throw INTERP_KERNEL::Exception(oss.str().c_str());
358           }
359       int idx=_nodal_connec_index->back();
360       int val=idx+size+1;
361       _nodal_connec_index->pushBackSilent(val);
362       _nodal_connec->writeOnPlace(idx,type,nodalConnOfCell,size);
363       _types.insert(type);
364     }
365   else
366     {
367       std::ostringstream oss; oss << "MEDCouplingUMesh::insertNextCell : cell type " << cm.getRepr() << " has a dimension " << cm.getDimension();
368       oss << " whereas Mesh Dimension of current UMesh instance is set to " << _mesh_dim << " ! Please invoke \"setMeshDimension\" method before or invoke ";
369       oss << "\"MEDCouplingUMesh::New\" static method with 2 parameters name and meshDimension !";
370       throw INTERP_KERNEL::Exception(oss.str().c_str());
371     }
372 }
373
374 /*!
375  * Compacts data arrays to release unused memory. This method is to be called after
376  * finishing cell insertion using \a this->insertNextCell().
377  * 
378  *  \if ENABLE_EXAMPLES
379  *  \ref medcouplingcppexamplesUmeshStdBuild1 "Here is a C++ example".<br>
380  *  \ref medcouplingpyexamplesUmeshStdBuild1 "Here is a Python example".
381  *  \endif
382  */
383 void MEDCouplingUMesh::finishInsertingCells()
384 {
385   _nodal_connec->pack();
386   _nodal_connec_index->pack();
387   _nodal_connec->declareAsNew();
388   _nodal_connec_index->declareAsNew();
389   updateTime();
390 }
391
392 /*!
393  * Entry point for iteration over cells of this. Warning the returned cell iterator should be deallocated.
394  * Useful for python users.
395  */
396 MEDCouplingUMeshCellIterator *MEDCouplingUMesh::cellIterator()
397 {
398   return new MEDCouplingUMeshCellIterator(this);
399 }
400
401 /*!
402  * Entry point for iteration over cells groups geo types per geotypes. Warning the returned cell iterator should be deallocated.
403  * If \a this is not so that that cells are grouped by geo types this method will throw an exception.
404  * In this case MEDCouplingUMesh::sortCellsInMEDFileFrmt or MEDCouplingUMesh::rearrange2ConsecutiveCellTypes methods for example can be called before invoking this method.
405  * Useful for python users.
406  */
407 MEDCouplingUMeshCellByTypeEntry *MEDCouplingUMesh::cellsByType()
408 {
409   if(!checkConsecutiveCellTypes())
410     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::cellsByType : this mesh is not sorted by type !");
411   return new MEDCouplingUMeshCellByTypeEntry(this);
412 }
413
414 /*!
415  * Returns a set of all cell types available in \a this mesh.
416  * \return std::set<INTERP_KERNEL::NormalizedCellType> - the set of cell types.
417  * \warning this method does not throw any exception even if \a this is not defined.
418  * \sa MEDCouplingUMesh::getAllGeoTypesSorted
419  */
420 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypes() const
421 {
422   return _types;
423 }
424
425 /*!
426  * This method returns the sorted list of geometric types in \a this.
427  * 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
428  * having the same geometric type. So a same geometric type can appear more than once if the cells are not sorted per geometric type.
429  *
430  * \throw if connectivity in \a this is not correctly defined.
431  *  
432  * \sa MEDCouplingMesh::getAllGeoTypes
433  */
434 std::vector<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getAllGeoTypesSorted() const
435 {
436   std::vector<INTERP_KERNEL::NormalizedCellType> ret;
437   checkConnectivityFullyDefined();
438   int nbOfCells(getNumberOfCells());
439   if(nbOfCells==0)
440     return ret;
441   if(getNodalConnectivityArrayLen()<1)
442     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAllGeoTypesSorted : the connectivity in this seems invalid !");
443   const int *c(_nodal_connec->begin()),*ci(_nodal_connec_index->begin());
444   ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci++]);
445   for(int i=1;i<nbOfCells;i++,ci++)
446     if(ret.back()!=((INTERP_KERNEL::NormalizedCellType)c[*ci]))
447       ret.push_back((INTERP_KERNEL::NormalizedCellType)c[*ci]);
448   return ret;
449 }
450
451 /*!
452  * This method is a method that compares \a this and \a other.
453  * This method compares \b all attributes, even names and component names.
454  */
455 bool MEDCouplingUMesh::isEqualIfNotWhy(const MEDCouplingMesh *other, double prec, std::string& reason) const
456 {
457   if(!other)
458     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isEqualIfNotWhy : input other pointer is null !");
459   std::ostringstream oss; oss.precision(15);
460   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
461   if(!otherC)
462     {
463       reason="mesh given in input is not castable in MEDCouplingUMesh !";
464       return false;
465     }
466   if(!MEDCouplingPointSet::isEqualIfNotWhy(other,prec,reason))
467     return false;
468   if(_mesh_dim!=otherC->_mesh_dim)
469     {
470       oss << "umesh dimension mismatch : this mesh dimension=" << _mesh_dim << " other mesh dimension=" <<  otherC->_mesh_dim;
471       reason=oss.str();
472       return false;
473     }
474   if(_types!=otherC->_types)
475     {
476       oss << "umesh geometric type mismatch :\nThis geometric types are :";
477       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
478         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
479       oss << "\nOther geometric types are :";
480       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=otherC->_types.begin();iter!=otherC->_types.end();iter++)
481         { const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter); oss << cm.getRepr() << ", "; }
482       reason=oss.str();
483       return false;
484     }
485   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
486     if(_nodal_connec==0 || otherC->_nodal_connec==0)
487       {
488         reason="Only one UMesh between the two this and other has its nodal connectivity DataArrayInt defined !";
489         return false;
490       }
491   if(_nodal_connec!=otherC->_nodal_connec)
492     if(!_nodal_connec->isEqualIfNotWhy(*otherC->_nodal_connec,reason))
493       {
494         reason.insert(0,"Nodal connectivity DataArrayInt differ : ");
495         return false;
496       }
497   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
498     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
499       {
500         reason="Only one UMesh between the two this and other has its nodal connectivity index DataArrayInt defined !";
501         return false;
502       }
503   if(_nodal_connec_index!=otherC->_nodal_connec_index)
504     if(!_nodal_connec_index->isEqualIfNotWhy(*otherC->_nodal_connec_index,reason))
505       {
506         reason.insert(0,"Nodal connectivity index DataArrayInt differ : ");
507         return false;
508       }
509   return true;
510 }
511
512 /*!
513  * Checks if data arrays of this mesh (node coordinates, nodal
514  * connectivity of cells, etc) of two meshes are same. Textual data like name etc. are
515  * not considered.
516  *  \param [in] other - the mesh to compare with.
517  *  \param [in] prec - precision value used to compare node coordinates.
518  *  \return bool - \a true if the two meshes are same.
519  */
520 bool MEDCouplingUMesh::isEqualWithoutConsideringStr(const MEDCouplingMesh *other, double prec) const
521 {
522   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
523   if(!otherC)
524     return false;
525   if(!MEDCouplingPointSet::isEqualWithoutConsideringStr(other,prec))
526     return false;
527   if(_mesh_dim!=otherC->_mesh_dim)
528     return false;
529   if(_types!=otherC->_types)
530     return false;
531   if(_nodal_connec!=0 || otherC->_nodal_connec!=0)
532     if(_nodal_connec==0 || otherC->_nodal_connec==0)
533       return false;
534   if(_nodal_connec!=otherC->_nodal_connec)
535     if(!_nodal_connec->isEqualWithoutConsideringStr(*otherC->_nodal_connec))
536       return false;
537   if(_nodal_connec_index!=0 || otherC->_nodal_connec_index!=0)
538     if(_nodal_connec_index==0 || otherC->_nodal_connec_index==0)
539       return false;
540   if(_nodal_connec_index!=otherC->_nodal_connec_index)
541     if(!_nodal_connec_index->isEqualWithoutConsideringStr(*otherC->_nodal_connec_index))
542       return false;
543   return true;
544 }
545
546 /*!
547  * Checks if \a this and \a other meshes are geometrically equivalent with high
548  * probability, else an exception is thrown. The meshes are considered equivalent if
549  * (1) meshes contain the same number of nodes and the same number of elements of the
550  * same types (2) three cells of the two meshes (first, last and middle) are based
551  * on coincident nodes (with a specified precision).
552  *  \param [in] other - the mesh to compare with.
553  *  \param [in] prec - the precision used to compare nodes of the two meshes.
554  *  \throw If the two meshes do not match.
555  */
556 void MEDCouplingUMesh::checkFastEquivalWith(const MEDCouplingMesh *other, double prec) const
557 {
558   MEDCouplingPointSet::checkFastEquivalWith(other,prec);
559   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
560   if(!otherC)
561     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkFastEquivalWith : Two meshes are not not unstructured !"); 
562 }
563
564 /*!
565  * Returns the reverse nodal connectivity. The reverse nodal connectivity enumerates
566  * cells each node belongs to.
567  * \warning For speed reasons, this method does not check if node ids in the nodal
568  *          connectivity correspond to the size of node coordinates array.
569  * \param [in,out] revNodal - an array holding ids of cells sharing each node.
570  * \param [in,out] revNodalIndx - an array, of length \a this->getNumberOfNodes() + 1,
571  *        dividing cell ids in \a revNodal into groups each referring to one
572  *        node. Its every element (except the last one) is an index pointing to the
573  *         first id of a group of cells. For example cells sharing the node #1 are 
574  *        described by following range of indices: 
575  *        [ \a revNodalIndx[1], \a revNodalIndx[2] ) and the cell ids are
576  *        \a revNodal[ \a revNodalIndx[1] ], \a revNodal[ \a revNodalIndx[1] + 1], ...
577  *        Number of cells sharing the *i*-th node is
578  *        \a revNodalIndx[ *i*+1 ] - \a revNodalIndx[ *i* ].
579  * \throw If the coordinates array is not set.
580  * \throw If the nodal connectivity of cells is not defined.
581  * 
582  * \if ENABLE_EXAMPLES
583  * \ref cpp_mcumesh_getReverseNodalConnectivity "Here is a C++ example".<br>
584  * \ref  py_mcumesh_getReverseNodalConnectivity "Here is a Python example".
585  * \endif
586  */
587 void MEDCouplingUMesh::getReverseNodalConnectivity(DataArrayInt *revNodal, DataArrayInt *revNodalIndx) const
588 {
589   checkFullyDefined();
590   int nbOfNodes=getNumberOfNodes();
591   int *revNodalIndxPtr=(int *)malloc((nbOfNodes+1)*sizeof(int));
592   revNodalIndx->useArray(revNodalIndxPtr,true,C_DEALLOC,nbOfNodes+1,1);
593   std::fill(revNodalIndxPtr,revNodalIndxPtr+nbOfNodes+1,0);
594   const int *conn=_nodal_connec->getConstPointer();
595   const int *connIndex=_nodal_connec_index->getConstPointer();
596   int nbOfCells=getNumberOfCells();
597   int nbOfEltsInRevNodal=0;
598   for(int eltId=0;eltId<nbOfCells;eltId++)
599     {
600       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
601       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
602       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
603         if(*iter>=0)//for polyhedrons
604           {
605             nbOfEltsInRevNodal++;
606             revNodalIndxPtr[(*iter)+1]++;
607           }
608     }
609   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
610   int *revNodalPtr=(int *)malloc((nbOfEltsInRevNodal)*sizeof(int));
611   revNodal->useArray(revNodalPtr,true,C_DEALLOC,nbOfEltsInRevNodal,1);
612   std::fill(revNodalPtr,revNodalPtr+nbOfEltsInRevNodal,-1);
613   for(int eltId=0;eltId<nbOfCells;eltId++)
614     {
615       const int *strtNdlConnOfCurCell=conn+connIndex[eltId]+1;
616       const int *endNdlConnOfCurCell=conn+connIndex[eltId+1];
617       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
618         if(*iter>=0)//for polyhedrons
619           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
620     }
621 }
622
623 /// @cond INTERNAL
624
625 int MEDCouplingFastNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
626 {
627   return id;
628 }
629
630 int MEDCouplingOrientationSensitiveNbrer(int id, unsigned nb, const INTERP_KERNEL::CellModel& cm, bool compute, const int *conn1, const int *conn2)
631 {
632   if(!compute)
633     return id+1;
634   else
635     {
636       if(cm.getOrientationStatus(nb,conn1,conn2))
637         return id+1;
638       else
639         return -(id+1);
640     }
641 }
642
643 class MinusOneSonsGenerator
644 {
645 public:
646   MinusOneSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
647   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
648   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity2(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
649   static const int DELTA=1;
650 private:
651   const INTERP_KERNEL::CellModel& _cm;
652 };
653
654 class MinusOneSonsGeneratorBiQuadratic
655 {
656 public:
657   MinusOneSonsGeneratorBiQuadratic(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
658   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfSons2(conn,lgth); }
659   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonCellNodalConnectivity4(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
660   static const int DELTA=1;
661 private:
662   const INTERP_KERNEL::CellModel& _cm;
663 };
664
665 class MinusTwoSonsGenerator
666 {
667 public:
668   MinusTwoSonsGenerator(const INTERP_KERNEL::CellModel& cm):_cm(cm) { }
669   unsigned getNumberOfSons2(const int *conn, int lgth) const { return _cm.getNumberOfEdgesIn3D(conn,lgth); }
670   unsigned fillSonCellNodalConnectivity2(int sonId, const int *nodalConn, int lgth, int *sonNodalConn, INTERP_KERNEL::NormalizedCellType& typeOfSon) const { return _cm.fillSonEdgesNodalConnectivity3D(sonId,nodalConn,lgth,sonNodalConn,typeOfSon); }
671   static const int DELTA=2;
672 private:
673   const INTERP_KERNEL::CellModel& _cm;
674 };
675
676 /// @endcond
677
678 /*!
679  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
680  * this->getMeshDimension(), that bound cells of \a this mesh. In addition arrays
681  * describing correspondence between cells of \a this and the result meshes are
682  * returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending connectivity,
683  * i.e. enumerate cells of the result mesh bounding each cell of \a this mesh. The
684  * arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
685  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh. 
686  * \warning For speed reasons, this method does not check if node ids in the nodal
687  *          connectivity correspond to the size of node coordinates array.
688  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
689  *          to write this mesh to the MED file, its cells must be sorted using
690  *          sortCellsInMEDFileFrmt().
691  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
692  *         each cell of \a this mesh.
693  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
694  *        dividing cell ids in \a desc into groups each referring to one
695  *        cell of \a this mesh. Its every element (except the last one) is an index
696  *        pointing to the first id of a group of cells. For example cells of the
697  *        result mesh bounding the cell #1 of \a this mesh are described by following
698  *        range of indices:
699  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
700  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
701  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
702  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
703  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
704  *         by each cell of the result mesh.
705  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
706  *        in the result mesh,
707  *        dividing cell ids in \a revDesc into groups each referring to one
708  *        cell of the result mesh the same way as \a descIndx divides \a desc.
709  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is to
710  *        delete this mesh using decrRef() as it is no more needed.
711  *  \throw If the coordinates array is not set.
712  *  \throw If the nodal connectivity of cells is node defined.
713  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
714  *         revDescIndx == NULL.
715  * 
716  *  \if ENABLE_EXAMPLES
717  *  \ref cpp_mcumesh_buildDescendingConnectivity "Here is a C++ example".<br>
718  *  \ref  py_mcumesh_buildDescendingConnectivity "Here is a Python example".
719  *  \endif
720  * \sa buildDescendingConnectivity2()
721  */
722 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
723 {
724   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
725 }
726
727 /*!
728  * \a this has to have a mesh dimension equal to 3. If it is not the case an INTERP_KERNEL::Exception will be thrown.
729  * This behaves exactly as MEDCouplingUMesh::buildDescendingConnectivity does except that this method compute directly the transition from mesh dimension 3 to sub edges (dimension 1)
730  * in one shot. That is to say that this method is equivalent to 2 successive calls to MEDCouplingUMesh::buildDescendingConnectivity.
731  * This method returns 4 arrays and a mesh as MEDCouplingUMesh::buildDescendingConnectivity does.
732  * \sa MEDCouplingUMesh::buildDescendingConnectivity
733  */
734 MEDCouplingUMesh *MEDCouplingUMesh::explode3DMeshTo1D(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
735 {
736   checkFullyDefined();
737   if(getMeshDimension()!=3)
738     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::explode3DMeshTo1D : This has to have a mesh dimension to 3 !");
739   return buildDescendingConnectivityGen<MinusTwoSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingFastNbrer);
740 }
741
742 /*!
743  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
744  * this->getMeshDimension(), that bound cells of \a this mesh. In
745  * addition arrays describing correspondence between cells of \a this and the result
746  * meshes are returned. The arrays \a desc and \a descIndx (\ref numbering-indirect) describe the descending
747  * connectivity, i.e. enumerate cells of the result mesh bounding each cell of \a this
748  *  mesh. This method differs from buildDescendingConnectivity() in that apart
749  * from cell ids, \a desc returns mutual orientation of cells in \a this and the
750  * result meshes. So a positive id means that order of nodes in corresponding cells
751  * of two meshes is same, and a negative id means a reverse order of nodes. Since a
752  * cell with id #0 can't be negative, the array \a desc returns ids in FORTRAN mode,
753  * i.e. cell ids are one-based.
754  * Arrays \a revDesc and \a revDescIndx (\ref numbering-indirect) describe the reverse descending connectivity,
755  * i.e. enumerate cells of  \a this mesh bounded by each cell of the result mesh. 
756  * \warning For speed reasons, this method does not check if node ids in the nodal
757  *          connectivity correspond to the size of node coordinates array.
758  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
759  *          to write this mesh to the MED file, its cells must be sorted using
760  *          sortCellsInMEDFileFrmt().
761  *  \param [in,out] desc - the array containing cell ids of the result mesh bounding
762  *         each cell of \a this mesh.
763  *  \param [in,out] descIndx - the array, of length \a this->getNumberOfCells() + 1,
764  *        dividing cell ids in \a desc into groups each referring to one
765  *        cell of \a this mesh. Its every element (except the last one) is an index
766  *        pointing to the first id of a group of cells. For example cells of the
767  *        result mesh bounding the cell #1 of \a this mesh are described by following
768  *        range of indices:
769  *        [ \a descIndx[1], \a descIndx[2] ) and the cell ids are
770  *        \a desc[ \a descIndx[1] ], \a desc[ \a descIndx[1] + 1], ...
771  *        Number of cells of the result mesh sharing the *i*-th cell of \a this mesh is
772  *        \a descIndx[ *i*+1 ] - \a descIndx[ *i* ].
773  *  \param [in,out] revDesc - the array containing cell ids of \a this mesh bounded
774  *         by each cell of the result mesh.
775  *  \param [in,out] revDescIndx - the array, of length one more than number of cells
776  *        in the result mesh,
777  *        dividing cell ids in \a revDesc into groups each referring to one
778  *        cell of the result mesh the same way as \a descIndx divides \a desc.
779  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This result mesh
780  *        shares the node coordinates array with \a this mesh. The caller is to
781  *        delete this mesh using decrRef() as it is no more needed.
782  *  \throw If the coordinates array is not set.
783  *  \throw If the nodal connectivity of cells is node defined.
784  *  \throw If \a desc == NULL || \a descIndx == NULL || \a revDesc == NULL || \a
785  *         revDescIndx == NULL.
786  * 
787  *  \if ENABLE_EXAMPLES
788  *  \ref cpp_mcumesh_buildDescendingConnectivity2 "Here is a C++ example".<br>
789  *  \ref  py_mcumesh_buildDescendingConnectivity2 "Here is a Python example".
790  *  \endif
791  * \sa buildDescendingConnectivity()
792  */
793 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivity2(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx) const
794 {
795   return buildDescendingConnectivityGen<MinusOneSonsGenerator>(desc,descIndx,revDesc,revDescIndx,MEDCouplingOrientationSensitiveNbrer);
796 }
797
798 /*!
799  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
800  * For speed reasons no check of this will be done. This method calls
801  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
802  * This method lists cell by cell in \b this which are its neighbors. To compute the result
803  * only connectivities are considered.
804  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
805  * The format of return is hence \ref numbering-indirect.
806  *
807  * \param [out] neighbors is an array storing all the neighbors of all cells in \b this. This array is newly
808  * allocated and should be dealt by the caller. \b neighborsIndx 2nd output
809  * parameter allows to select the right part in this array (\ref numbering-indirect). The number of tuples
810  * is equal to the last values in \b neighborsIndx.
811  * \param [out] neighborsIndx is an array of size this->getNumberOfCells()+1 newly allocated and should be
812  * dealt by the caller. This arrays allow to use the first output parameter \b neighbors (\ref numbering-indirect).
813  */
814 void MEDCouplingUMesh::computeNeighborsOfCells(DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx) const
815 {
816   MCAuto<DataArrayInt> desc=DataArrayInt::New();
817   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
818   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
819   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
820   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
821   meshDM1=0;
822   ComputeNeighborsOfCellsAdv(desc,descIndx,revDesc,revDescIndx,neighbors,neighborsIndx);
823 }
824
825 /*!
826  * This method is called by MEDCouplingUMesh::computeNeighborsOfCells. This methods performs the algorithm
827  * of MEDCouplingUMesh::computeNeighborsOfCells.
828  * This method is useful for users that want to reduce along a criterion the set of neighbours cell. This is
829  * typically the case to extract a set a neighbours,
830  * excluding a set of meshdim-1 cells in input descending connectivity.
831  * Typically \b desc, \b descIndx, \b revDesc and \b revDescIndx (\ref numbering-indirect) input params are
832  * the result of MEDCouplingUMesh::buildDescendingConnectivity.
833  * This method lists cell by cell in \b this which are its neighbors. To compute the result only connectivities
834  * are considered.
835  * The neighbor cells of cell having id 'cellId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
836  *
837  * \param [in] desc descending connectivity array.
838  * \param [in] descIndx descending connectivity index array used to walk through \b desc (\ref numbering-indirect).
839  * \param [in] revDesc reverse descending connectivity array.
840  * \param [in] revDescIndx reverse descending connectivity index array used to walk through \b revDesc (\ref numbering-indirect).
841  * \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
842  *                        parameter allows to select the right part in this array. The number of tuples is equal to the last values in \b neighborsIndx.
843  * \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.
844  */
845 void MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(const DataArrayInt *desc, const DataArrayInt *descIndx, const DataArrayInt *revDesc, const DataArrayInt *revDescIndx,
846                                                   DataArrayInt *&neighbors, DataArrayInt *&neighborsIndx)
847 {
848   if(!desc || !descIndx || !revDesc || !revDescIndx)
849     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeNeighborsOfCellsAdv some input array is empty !");
850   const int *descPtr=desc->getConstPointer();
851   const int *descIPtr=descIndx->getConstPointer();
852   const int *revDescPtr=revDesc->getConstPointer();
853   const int *revDescIPtr=revDescIndx->getConstPointer();
854   //
855   int nbCells=descIndx->getNumberOfTuples()-1;
856   MCAuto<DataArrayInt> out0=DataArrayInt::New();
857   MCAuto<DataArrayInt> out1=DataArrayInt::New(); out1->alloc(nbCells+1,1);
858   int *out1Ptr=out1->getPointer();
859   *out1Ptr++=0;
860   out0->reserve(desc->getNumberOfTuples());
861   for(int i=0;i<nbCells;i++,descIPtr++,out1Ptr++)
862     {
863       for(const int *w1=descPtr+descIPtr[0];w1!=descPtr+descIPtr[1];w1++)
864         {
865           std::set<int> s(revDescPtr+revDescIPtr[*w1],revDescPtr+revDescIPtr[(*w1)+1]);
866           s.erase(i);
867           out0->insertAtTheEnd(s.begin(),s.end());
868         }
869       *out1Ptr=out0->getNumberOfTuples();
870     }
871   neighbors=out0.retn();
872   neighborsIndx=out1.retn();
873 }
874
875 /*!
876  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
877  * For speed reasons no check of this will be done. This method calls
878  * MEDCouplingUMesh::buildDescendingConnectivity to compute the result.
879  * This method lists node by node in \b this which are its neighbors. To compute the result
880  * only connectivities are considered.
881  * The neighbor nodes of node having id 'nodeId' are neighbors[neighborsIndx[cellId]:neighborsIndx[cellId+1]].
882  *
883  * \param [out] neighbors is an array storing all the neighbors of all nodes in \b this. This array
884  * is newly allocated and should be dealt by the caller. \b neighborsIndx 2nd output
885  * parameter allows to select the right part in this array (\ref numbering-indirect).
886  * The number of tuples is equal to the last values in \b neighborsIndx.
887  * \param [out] neighborsIdx is an array of size this->getNumberOfCells()+1 newly allocated and should
888  * be dealt by the caller. This arrays allow to use the first output parameter \b neighbors.
889  */
890 void MEDCouplingUMesh::computeNeighborsOfNodes(DataArrayInt *&neighbors, DataArrayInt *&neighborsIdx) const
891 {
892   checkFullyDefined();
893   int mdim(getMeshDimension()),nbNodes(getNumberOfNodes());
894   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descIndx(DataArrayInt::New()),revDesc(DataArrayInt::New()),revDescIndx(DataArrayInt::New());
895   MCAuto<MEDCouplingUMesh> mesh1D;
896   switch(mdim)
897   {
898     case 3:
899       {
900         mesh1D=explode3DMeshTo1D(desc,descIndx,revDesc,revDescIndx);
901         break;
902       }
903     case 2:
904       {
905         mesh1D=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
906         break;
907       }
908     case 1:
909       {
910         mesh1D=const_cast<MEDCouplingUMesh *>(this);
911         mesh1D->incrRef();
912         break;
913       }
914     default:
915       {
916         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computeNeighborsOfNodes : Mesh dimension supported are [3,2,1] !");
917       }
918   }
919   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=0; revDescIndx=0;
920   mesh1D->getReverseNodalConnectivity(desc,descIndx);
921   MCAuto<DataArrayInt> ret0(DataArrayInt::New());
922   ret0->alloc(desc->getNumberOfTuples(),1);
923   int *r0Pt(ret0->getPointer());
924   const int *c1DPtr(mesh1D->getNodalConnectivity()->begin()),*rn(desc->begin()),*rni(descIndx->begin());
925   for(int i=0;i<nbNodes;i++,rni++)
926     {
927       for(const int *oneDCellIt=rn+rni[0];oneDCellIt!=rn+rni[1];oneDCellIt++)
928         *r0Pt++=c1DPtr[3*(*oneDCellIt)+1]==i?c1DPtr[3*(*oneDCellIt)+2]:c1DPtr[3*(*oneDCellIt)+1];
929     }
930   neighbors=ret0.retn();
931   neighborsIdx=descIndx.retn();
932 }
933
934 /// @cond INTERNAL
935
936 /*!
937  * \b WARNING this method do the assumption that connectivity lies on the coordinates set.
938  * For speed reasons no check of this will be done.
939  */
940 template<class SonsGenerator>
941 MEDCouplingUMesh *MEDCouplingUMesh::buildDescendingConnectivityGen(DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *revDesc, DataArrayInt *revDescIndx, DimM1DescNbrer nbrer) const
942 {
943   if(!desc || !descIndx || !revDesc || !revDescIndx)
944     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildDescendingConnectivityGen : present of a null pointer in input !");
945   checkConnectivityFullyDefined();
946   int nbOfCells=getNumberOfCells();
947   int nbOfNodes=getNumberOfNodes();
948   MCAuto<DataArrayInt> revNodalIndx=DataArrayInt::New(); revNodalIndx->alloc(nbOfNodes+1,1); revNodalIndx->fillWithZero();
949   int *revNodalIndxPtr=revNodalIndx->getPointer();
950   const int *conn=_nodal_connec->getConstPointer();
951   const int *connIndex=_nodal_connec_index->getConstPointer();
952   std::string name="Mesh constituent of "; name+=getName();
953   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(name,getMeshDimension()-SonsGenerator::DELTA);
954   ret->setCoords(getCoords());
955   ret->allocateCells(2*nbOfCells);
956   descIndx->alloc(nbOfCells+1,1);
957   MCAuto<DataArrayInt> revDesc2(DataArrayInt::New()); revDesc2->reserve(2*nbOfCells);
958   int *descIndxPtr=descIndx->getPointer(); *descIndxPtr++=0;
959   for(int eltId=0;eltId<nbOfCells;eltId++,descIndxPtr++)
960     {
961       int pos=connIndex[eltId];
962       int posP1=connIndex[eltId+1];
963       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[pos]);
964       SonsGenerator sg(cm);
965       unsigned nbOfSons=sg.getNumberOfSons2(conn+pos+1,posP1-pos-1);
966       INTERP_KERNEL::AutoPtr<int> tmp=new int[posP1-pos];
967       for(unsigned i=0;i<nbOfSons;i++)
968         {
969           INTERP_KERNEL::NormalizedCellType cmsId;
970           unsigned nbOfNodesSon=sg.fillSonCellNodalConnectivity2(i,conn+pos+1,posP1-pos-1,tmp,cmsId);
971           for(unsigned k=0;k<nbOfNodesSon;k++)
972             if(tmp[k]>=0)
973               revNodalIndxPtr[tmp[k]+1]++;
974           ret->insertNextCell(cmsId,nbOfNodesSon,tmp);
975           revDesc2->pushBackSilent(eltId);
976         }
977       descIndxPtr[0]=descIndxPtr[-1]+(int)nbOfSons;
978     }
979   int nbOfCellsM1=ret->getNumberOfCells();
980   std::transform(revNodalIndxPtr+1,revNodalIndxPtr+nbOfNodes+1,revNodalIndxPtr,revNodalIndxPtr+1,std::plus<int>());
981   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(); revNodal->alloc(revNodalIndx->back(),1);
982   std::fill(revNodal->getPointer(),revNodal->getPointer()+revNodalIndx->back(),-1);
983   int *revNodalPtr=revNodal->getPointer();
984   const int *connM1=ret->getNodalConnectivity()->getConstPointer();
985   const int *connIndexM1=ret->getNodalConnectivityIndex()->getConstPointer();
986   for(int eltId=0;eltId<nbOfCellsM1;eltId++)
987     {
988       const int *strtNdlConnOfCurCell=connM1+connIndexM1[eltId]+1;
989       const int *endNdlConnOfCurCell=connM1+connIndexM1[eltId+1];
990       for(const int *iter=strtNdlConnOfCurCell;iter!=endNdlConnOfCurCell;iter++)
991         if(*iter>=0)//for polyhedrons
992           *std::find_if(revNodalPtr+revNodalIndxPtr[*iter],revNodalPtr+revNodalIndxPtr[*iter+1],std::bind2nd(std::equal_to<int>(),-1))=eltId;
993     }
994   //
995   DataArrayInt *commonCells=0,*commonCellsI=0;
996   FindCommonCellsAlg(3,0,ret->getNodalConnectivity(),ret->getNodalConnectivityIndex(),revNodal,revNodalIndx,commonCells,commonCellsI);
997   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
998   const int *commonCellsPtr(commonCells->getConstPointer()),*commonCellsIPtr(commonCellsI->getConstPointer());
999   int newNbOfCellsM1=-1;
1000   MCAuto<DataArrayInt> o2nM1=DataArrayInt::ConvertIndexArrayToO2N(nbOfCellsM1,commonCells->begin(),
1001                                                                                                             commonCellsI->begin(),commonCellsI->end(),newNbOfCellsM1);
1002   std::vector<bool> isImpacted(nbOfCellsM1,false);
1003   for(const int *work=commonCellsI->begin();work!=commonCellsI->end()-1;work++)
1004     for(int work2=work[0];work2!=work[1];work2++)
1005       isImpacted[commonCellsPtr[work2]]=true;
1006   const int *o2nM1Ptr=o2nM1->getConstPointer();
1007   MCAuto<DataArrayInt> n2oM1=o2nM1->invertArrayO2N2N2OBis(newNbOfCellsM1);
1008   const int *n2oM1Ptr=n2oM1->getConstPointer();
1009   MCAuto<MEDCouplingUMesh> ret2=static_cast<MEDCouplingUMesh *>(ret->buildPartOfMySelf(n2oM1->begin(),n2oM1->end(),true));
1010   ret2->copyTinyInfoFrom(this);
1011   desc->alloc(descIndx->back(),1);
1012   int *descPtr=desc->getPointer();
1013   const INTERP_KERNEL::CellModel& cmsDft=INTERP_KERNEL::CellModel::GetCellModel(INTERP_KERNEL::NORM_POINT1);
1014   for(int i=0;i<nbOfCellsM1;i++,descPtr++)
1015     {
1016       if(!isImpacted[i])
1017         *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1018       else
1019         {
1020           if(i!=n2oM1Ptr[o2nM1Ptr[i]])
1021             {
1022               const INTERP_KERNEL::CellModel& cms=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connM1[connIndexM1[i]]);
1023               *descPtr=nbrer(o2nM1Ptr[i],connIndexM1[i+1]-connIndexM1[i]-1,cms,true,connM1+connIndexM1[n2oM1Ptr[o2nM1Ptr[i]]]+1,connM1+connIndexM1[i]+1);
1024             }
1025           else
1026             *descPtr=nbrer(o2nM1Ptr[i],0,cmsDft,false,0,0);
1027         }
1028     }
1029   revDesc->reserve(newNbOfCellsM1);
1030   revDescIndx->alloc(newNbOfCellsM1+1,1);
1031   int *revDescIndxPtr=revDescIndx->getPointer(); *revDescIndxPtr++=0;
1032   const int *revDesc2Ptr=revDesc2->getConstPointer();
1033   for(int i=0;i<newNbOfCellsM1;i++,revDescIndxPtr++)
1034     {
1035       int oldCellIdM1=n2oM1Ptr[i];
1036       if(!isImpacted[oldCellIdM1])
1037         {
1038           revDesc->pushBackSilent(revDesc2Ptr[oldCellIdM1]);
1039           revDescIndxPtr[0]=revDescIndxPtr[-1]+1;
1040         }
1041       else
1042         {
1043           for(int j=commonCellsIPtr[0];j<commonCellsIPtr[1];j++)
1044             revDesc->pushBackSilent(revDesc2Ptr[commonCellsPtr[j]]);
1045           revDescIndxPtr[0]=revDescIndxPtr[-1]+commonCellsIPtr[1]-commonCellsIPtr[0];
1046           commonCellsIPtr++;
1047         }
1048     }
1049   //
1050   return ret2.retn();
1051 }
1052
1053 struct MEDCouplingAccVisit
1054 {
1055   MEDCouplingAccVisit():_new_nb_of_nodes(0) { }
1056   int operator()(int val) { if(val!=-1) return _new_nb_of_nodes++; else return -1; }
1057   int _new_nb_of_nodes;
1058 };
1059
1060 /// @endcond
1061
1062 /*!
1063  * Converts specified cells to either polygons (if \a this is a 2D mesh) or
1064  * polyhedrons (if \a this is a 3D mesh). The cells to convert are specified by an
1065  * array of cell ids. Pay attention that after conversion all algorithms work slower
1066  * with \a this mesh than before conversion. <br> If an exception is thrown during the
1067  * conversion due presence of invalid ids in the array of cells to convert, as a
1068  * result \a this mesh contains some already converted elements. In this case the 2D
1069  * mesh remains valid but 3D mesh becomes \b inconsistent!
1070  *  \warning This method can significantly modify the order of geometric types in \a this,
1071  *          hence, to write this mesh to the MED file, its cells must be sorted using
1072  *          sortCellsInMEDFileFrmt().
1073  *  \param [in] cellIdsToConvertBg - the array holding ids of cells to convert.
1074  *  \param [in] cellIdsToConvertEnd - a pointer to the last-plus-one-th element of \a
1075  *         cellIdsToConvertBg.
1076  *  \throw If the coordinates array is not set.
1077  *  \throw If the nodal connectivity of cells is node defined.
1078  *  \throw If dimension of \a this mesh is not either 2 or 3.
1079  *
1080  *  \if ENABLE_EXAMPLES
1081  *  \ref cpp_mcumesh_convertToPolyTypes "Here is a C++ example".<br>
1082  *  \ref  py_mcumesh_convertToPolyTypes "Here is a Python example".
1083  *  \endif
1084  */
1085 void MEDCouplingUMesh::convertToPolyTypes(const int *cellIdsToConvertBg, const int *cellIdsToConvertEnd)
1086 {
1087   checkFullyDefined();
1088   int dim=getMeshDimension();
1089   if(dim<2 || dim>3)
1090     throw INTERP_KERNEL::Exception("Invalid mesh dimension : must be 2 or 3 !");
1091   int nbOfCells(getNumberOfCells());
1092   if(dim==2)
1093     {
1094       const int *connIndex=_nodal_connec_index->getConstPointer();
1095       int *conn=_nodal_connec->getPointer();
1096       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1097         {
1098           if(*iter>=0 && *iter<nbOfCells)
1099             {
1100               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*iter]]);
1101               if(!cm.isQuadratic())
1102                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_POLYGON;
1103               else
1104                 conn[connIndex[*iter]]=INTERP_KERNEL::NORM_QPOLYG;
1105             }
1106           else
1107             {
1108               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1109               oss << " in range [0," << nbOfCells << ") !";
1110               throw INTERP_KERNEL::Exception(oss.str().c_str());
1111             }
1112         }
1113     }
1114   else
1115     {
1116       int *connIndex(_nodal_connec_index->getPointer());
1117       const int *connOld(_nodal_connec->getConstPointer());
1118       MCAuto<DataArrayInt> connNew(DataArrayInt::New()),connNewI(DataArrayInt::New()); connNew->alloc(0,1); connNewI->alloc(1,1); connNewI->setIJ(0,0,0);
1119       std::vector<bool> toBeDone(nbOfCells,false);
1120       for(const int *iter=cellIdsToConvertBg;iter!=cellIdsToConvertEnd;iter++)
1121         {
1122           if(*iter>=0 && *iter<nbOfCells)
1123             toBeDone[*iter]=true;
1124           else
1125             {
1126               std::ostringstream oss; oss << "MEDCouplingUMesh::convertToPolyTypes : On rank #" << std::distance(cellIdsToConvertBg,iter) << " value is " << *iter << " which is not";
1127               oss << " in range [0," << nbOfCells << ") !";
1128               throw INTERP_KERNEL::Exception(oss.str().c_str());
1129             }
1130         }
1131       for(int cellId=0;cellId<nbOfCells;cellId++)
1132         {
1133           int pos(connIndex[cellId]),posP1(connIndex[cellId+1]);
1134           int lgthOld(posP1-pos-1);
1135           if(toBeDone[cellId])
1136             {
1137               const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connOld[pos]);
1138               unsigned nbOfFaces(cm.getNumberOfSons2(connOld+pos+1,lgthOld));
1139               int *tmp(new int[nbOfFaces*lgthOld+1]);
1140               int *work=tmp; *work++=INTERP_KERNEL::NORM_POLYHED;
1141               for(unsigned j=0;j<nbOfFaces;j++)
1142                 {
1143                   INTERP_KERNEL::NormalizedCellType type;
1144                   unsigned offset=cm.fillSonCellNodalConnectivity2(j,connOld+pos+1,lgthOld,work,type);
1145                   work+=offset;
1146                   *work++=-1;
1147                 }
1148               std::size_t newLgth(std::distance(tmp,work)-1);//-1 for last -1
1149               connNew->pushBackValsSilent(tmp,tmp+newLgth);
1150               connNewI->pushBackSilent(connNewI->back()+(int)newLgth);
1151               delete [] tmp;
1152             }
1153           else
1154             {
1155               connNew->pushBackValsSilent(connOld+pos,connOld+posP1);
1156               connNewI->pushBackSilent(connNewI->back()+posP1-pos);
1157             }
1158         }
1159       setConnectivity(connNew,connNewI,false);//false because computeTypes called just behind.
1160     }
1161   computeTypes();
1162 }
1163
1164 /*!
1165  * Converts all cells to either polygons (if \a this is a 2D mesh) or
1166  * polyhedrons (if \a this is a 3D mesh).
1167  *  \warning As this method is purely for user-friendliness and no optimization is
1168  *          done to avoid construction of a useless vector, this method can be costly
1169  *          in memory.
1170  *  \throw If the coordinates array is not set.
1171  *  \throw If the nodal connectivity of cells is node defined.
1172  *  \throw If dimension of \a this mesh is not either 2 or 3.
1173  */
1174 void MEDCouplingUMesh::convertAllToPoly()
1175 {
1176   int nbOfCells=getNumberOfCells();
1177   std::vector<int> cellIds(nbOfCells);
1178   for(int i=0;i<nbOfCells;i++)
1179     cellIds[i]=i;
1180   convertToPolyTypes(&cellIds[0],&cellIds[0]+cellIds.size());
1181 }
1182
1183 /*!
1184  * Fixes nodal connectivity of invalid cells of type NORM_POLYHED. This method
1185  * expects that all NORM_POLYHED cells have connectivity similar to that of prismatic
1186  * volumes like NORM_HEXA8, NORM_PENTA6 etc., i.e. the first half of nodes describes a
1187  * base facet of the volume and the second half of nodes describes an opposite facet
1188  * having the same number of nodes as the base one. This method converts such
1189  * connectivity to a valid polyhedral format where connectivity of each facet is
1190  * explicitly described and connectivity of facets are separated by -1. If \a this mesh
1191  * contains a NORM_POLYHED cell with a valid connectivity, or an invalid connectivity is
1192  * not as expected, an exception is thrown and the mesh remains unchanged. Care of
1193  * a correct orientation of the first facet of a polyhedron, else orientation of a
1194  * corrected cell is reverse.<br>
1195  * This method is useful to build an extruded unstructured mesh with polyhedrons as
1196  * it releases the user from boring description of polyhedra connectivity in the valid
1197  * format.
1198  *  \throw If \a this->getMeshDimension() != 3.
1199  *  \throw If \a this->getSpaceDimension() != 3.
1200  *  \throw If the nodal connectivity of cells is not defined.
1201  *  \throw If the coordinates array is not set.
1202  *  \throw If \a this mesh contains polyhedrons with the valid connectivity.
1203  *  \throw If \a this mesh contains polyhedrons with odd number of nodes.
1204  *
1205  *  \if ENABLE_EXAMPLES
1206  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
1207  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
1208  *  \endif
1209  */
1210 void MEDCouplingUMesh::convertExtrudedPolyhedra()
1211 {
1212   checkFullyDefined();
1213   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1214     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertExtrudedPolyhedra works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
1215   int nbOfCells=getNumberOfCells();
1216   MCAuto<DataArrayInt> newCi=DataArrayInt::New();
1217   newCi->alloc(nbOfCells+1,1);
1218   int *newci=newCi->getPointer();
1219   const int *ci=_nodal_connec_index->getConstPointer();
1220   const int *c=_nodal_connec->getConstPointer();
1221   newci[0]=0;
1222   for(int i=0;i<nbOfCells;i++)
1223     {
1224       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1225       if(type==INTERP_KERNEL::NORM_POLYHED)
1226         {
1227           if(std::count(c+ci[i]+1,c+ci[i+1],-1)!=0)
1228             {
1229               std::ostringstream oss; oss << "MEDCouplingUMesh::convertExtrudedPolyhedra : cell # " << i << " is a polhedron BUT it has NOT exactly 1 face !";
1230               throw INTERP_KERNEL::Exception(oss.str().c_str());
1231             }
1232           std::size_t n2=std::distance(c+ci[i]+1,c+ci[i+1]);
1233           if(n2%2!=0)
1234             {
1235               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 !";
1236               throw INTERP_KERNEL::Exception(oss.str().c_str());
1237             }
1238           int n1=(int)(n2/2);
1239           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)
1240         }
1241       else
1242         newci[i+1]=(ci[i+1]-ci[i])+newci[i];
1243     }
1244   MCAuto<DataArrayInt> newC=DataArrayInt::New();
1245   newC->alloc(newci[nbOfCells],1);
1246   int *newc=newC->getPointer();
1247   for(int i=0;i<nbOfCells;i++)
1248     {
1249       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[i]];
1250       if(type==INTERP_KERNEL::NORM_POLYHED)
1251         {
1252           std::size_t n1=std::distance(c+ci[i]+1,c+ci[i+1])/2;
1253           newc=std::copy(c+ci[i],c+ci[i]+n1+1,newc);
1254           *newc++=-1;
1255           for(std::size_t j=0;j<n1;j++)
1256             {
1257               newc[j]=c[ci[i]+1+n1+(n1-j)%n1];
1258               newc[n1+5*j]=-1;
1259               newc[n1+5*j+1]=c[ci[i]+1+j];
1260               newc[n1+5*j+2]=c[ci[i]+1+j+n1];
1261               newc[n1+5*j+3]=c[ci[i]+1+(j+1)%n1+n1];
1262               newc[n1+5*j+4]=c[ci[i]+1+(j+1)%n1];
1263             }
1264           newc+=n1*6;
1265         }
1266       else
1267         newc=std::copy(c+ci[i],c+ci[i+1],newc);
1268     }
1269   _nodal_connec_index->decrRef(); _nodal_connec_index=newCi.retn();
1270   _nodal_connec->decrRef(); _nodal_connec=newC.retn();
1271 }
1272
1273
1274 /*!
1275  * Converts all polygons (if \a this is a 2D mesh) or polyhedrons (if \a this is a 3D
1276  * mesh) to cells of classical types. This method is opposite to convertToPolyTypes().
1277  * \warning Cells of the result mesh are \b not sorted by geometric type, hence,
1278  *          to write this mesh to the MED file, its cells must be sorted using
1279  *          sortCellsInMEDFileFrmt().
1280  * \warning Cells (and most notably polyhedrons) must be correctly oriented for this to work
1281  *          properly. See orientCorrectlyPolyhedrons() and arePolyhedronsNotCorrectlyOriented().
1282  * \return \c true if at least one cell has been converted, \c false else. In the
1283  *         last case the nodal connectivity remains unchanged.
1284  * \throw If the coordinates array is not set.
1285  * \throw If the nodal connectivity of cells is not defined.
1286  * \throw If \a this->getMeshDimension() < 0.
1287  */
1288 bool MEDCouplingUMesh::unPolyze()
1289 {
1290   checkFullyDefined();
1291   int mdim=getMeshDimension();
1292   if(mdim<0)
1293     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1294   if(mdim<=1)
1295     return false;
1296   int nbOfCells=getNumberOfCells();
1297   if(nbOfCells<1)
1298     return false;
1299   int initMeshLgth=getNodalConnectivityArrayLen();
1300   int *conn=_nodal_connec->getPointer();
1301   int *index=_nodal_connec_index->getPointer();
1302   int posOfCurCell=0;
1303   int newPos=0;
1304   int lgthOfCurCell;
1305   bool ret=false;
1306   for(int i=0;i<nbOfCells;i++)
1307     {
1308       lgthOfCurCell=index[i+1]-posOfCurCell;
1309       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1310       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1311       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1312       int newLgth;
1313       if(cm.isDynamic())
1314         {
1315           switch(cm.getDimension())
1316           {
1317             case 2:
1318               {
1319                 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1320                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1321                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1322                 break;
1323               }
1324             case 3:
1325               {
1326                 int nbOfFaces,lgthOfPolyhConn;
1327                 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1328                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1329                 break;
1330               }
1331             case 1:
1332               {
1333                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1334                 break;
1335               }
1336           }
1337           ret=ret || (newType!=type);
1338           conn[newPos]=newType;
1339           newPos+=newLgth+1;
1340           posOfCurCell=index[i+1];
1341           index[i+1]=newPos;
1342         }
1343       else
1344         {
1345           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1346           newPos+=lgthOfCurCell;
1347           posOfCurCell+=lgthOfCurCell;
1348           index[i+1]=newPos;
1349         }
1350     }
1351   if(newPos!=initMeshLgth)
1352     _nodal_connec->reAlloc(newPos);
1353   if(ret)
1354     computeTypes();
1355   return ret;
1356 }
1357
1358 /*!
1359  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1360  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1361  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. 
1362  *
1363  * \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 
1364  *             precision.
1365  */
1366 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1367 {
1368   checkFullyDefined();
1369   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1370     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1371   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1372   coords->recenterForMaxPrecision(eps);
1373   //
1374   int nbOfCells=getNumberOfCells();
1375   const int *conn=_nodal_connec->getConstPointer();
1376   const int *index=_nodal_connec_index->getConstPointer();
1377   MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1378   connINew->alloc(nbOfCells+1,1);
1379   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1380   MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1381   bool changed=false;
1382   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1383     {
1384       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1385         {
1386           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1387           changed=true;
1388         }
1389       else
1390         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1391       *connINewPtr=connNew->getNumberOfTuples();
1392     }
1393   if(changed)
1394     setConnectivity(connNew,connINew,false);
1395 }
1396
1397 /*!
1398  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1399  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1400  * the format of the returned DataArrayInt instance.
1401  * 
1402  * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1403  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1404  */
1405 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1406 {
1407   checkConnectivityFullyDefined();
1408   int nbOfCells=getNumberOfCells();
1409   const int *connIndex=_nodal_connec_index->getConstPointer();
1410   const int *conn=_nodal_connec->getConstPointer();
1411   const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1412   int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1413   std::vector<bool> retS(maxElt,false);
1414   for(int i=0;i<nbOfCells;i++)
1415     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1416       if(conn[j]>=0)
1417         retS[conn[j]]=true;
1418   int sz=0;
1419   for(int i=0;i<maxElt;i++)
1420     if(retS[i])
1421       sz++;
1422   DataArrayInt *ret=DataArrayInt::New();
1423   ret->alloc(sz,1);
1424   int *retPtr=ret->getPointer();
1425   for(int i=0;i<maxElt;i++)
1426     if(retS[i])
1427       *retPtr++=i;
1428   return ret;
1429 }
1430
1431 /*!
1432  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1433  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1434  */
1435 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1436 {
1437   int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1438   const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1439   for(int i=0;i<nbOfCells;i++)
1440     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1441       if(conn[j]>=0)
1442         {
1443           if(conn[j]<nbOfNodes)
1444             nodeIdsInUse[conn[j]]=true;
1445           else
1446             {
1447               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1448               throw INTERP_KERNEL::Exception(oss.str().c_str());
1449             }
1450         }
1451 }
1452
1453 /*!
1454  * Finds nodes not used in any cell and returns an array giving a new id to every node
1455  * by excluding the unused nodes, for which the array holds -1. The result array is
1456  * a mapping in "Old to New" mode. 
1457  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1458  *  \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1459  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1460  *          if the node is unused or a new id else. The caller is to delete this
1461  *          array using decrRef() as it is no more needed.  
1462  *  \throw If the coordinates array is not set.
1463  *  \throw If the nodal connectivity of cells is not defined.
1464  *  \throw If the nodal connectivity includes an invalid id.
1465  *
1466  *  \if ENABLE_EXAMPLES
1467  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1468  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1469  *  \endif
1470  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1471  */
1472 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1473 {
1474   nbrOfNodesInUse=-1;
1475   int nbOfNodes(getNumberOfNodes());
1476   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1477   ret->alloc(nbOfNodes,1);
1478   int *traducer=ret->getPointer();
1479   std::fill(traducer,traducer+nbOfNodes,-1);
1480   int nbOfCells=getNumberOfCells();
1481   const int *connIndex=_nodal_connec_index->getConstPointer();
1482   const int *conn=_nodal_connec->getConstPointer();
1483   for(int i=0;i<nbOfCells;i++)
1484     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1485       if(conn[j]>=0)
1486         {
1487           if(conn[j]<nbOfNodes)
1488             traducer[conn[j]]=1;
1489           else
1490             {
1491               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1492               throw INTERP_KERNEL::Exception(oss.str().c_str());
1493             }
1494         }
1495   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1496   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1497   return ret.retn();
1498 }
1499
1500 /*!
1501  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1502  * For each cell in \b this the number of nodes constituting cell is computed.
1503  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1504  * So for pohyhedrons some nodes can be counted several times in the returned result.
1505  * 
1506  * \return a newly allocated array
1507  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1508  */
1509 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1510 {
1511   checkConnectivityFullyDefined();
1512   int nbOfCells=getNumberOfCells();
1513   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1514   ret->alloc(nbOfCells,1);
1515   int *retPtr=ret->getPointer();
1516   const int *conn=getNodalConnectivity()->getConstPointer();
1517   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1518   for(int i=0;i<nbOfCells;i++,retPtr++)
1519     {
1520       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1521         *retPtr=connI[i+1]-connI[i]-1;
1522       else
1523         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1524     }
1525   return ret.retn();
1526 }
1527
1528 /*!
1529  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1530  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1531  *
1532  * \return DataArrayInt * - new object to be deallocated by the caller.
1533  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1534  */
1535 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1536 {
1537   checkConnectivityFullyDefined();
1538   int nbOfCells=getNumberOfCells();
1539   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1540   ret->alloc(nbOfCells,1);
1541   int *retPtr=ret->getPointer();
1542   const int *conn=getNodalConnectivity()->getConstPointer();
1543   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1544   for(int i=0;i<nbOfCells;i++,retPtr++)
1545     {
1546       std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1547       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1548         *retPtr=(int)s.size();
1549       else
1550         {
1551           s.erase(-1);
1552           *retPtr=(int)s.size();
1553         }
1554     }
1555   return ret.retn();
1556 }
1557
1558 /*!
1559  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1560  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1561  * 
1562  * \return a newly allocated array
1563  */
1564 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1565 {
1566   checkConnectivityFullyDefined();
1567   int nbOfCells=getNumberOfCells();
1568   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1569   ret->alloc(nbOfCells,1);
1570   int *retPtr=ret->getPointer();
1571   const int *conn=getNodalConnectivity()->getConstPointer();
1572   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1573   for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1574     {
1575       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1576       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1577     }
1578   return ret.retn();
1579 }
1580
1581 /*!
1582  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1583  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1584  * array mean that the corresponding old node is no more used. 
1585  *  \return DataArrayInt * - a new instance of DataArrayInt of length \a
1586  *           this->getNumberOfNodes() before call of this method. The caller is to
1587  *           delete this array using decrRef() as it is no more needed. 
1588  *  \throw If the coordinates array is not set.
1589  *  \throw If the nodal connectivity of cells is not defined.
1590  *  \throw If the nodal connectivity includes an invalid id.
1591  *  \sa areAllNodesFetched
1592  *
1593  *  \if ENABLE_EXAMPLES
1594  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1595  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1596  *  \endif
1597  */
1598 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1599 {
1600   return MEDCouplingPointSet::zipCoordsTraducer();
1601 }
1602
1603 /*!
1604  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1605  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1606  */
1607 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1608 {
1609   switch(compType)
1610   {
1611     case 0:
1612       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1613     case 1:
1614       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1615     case 2:
1616       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1617     case 3:
1618       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1619     case 7:
1620       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1621   }
1622   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1623 }
1624
1625 /*!
1626  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1627  */
1628 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1629 {
1630   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1631     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1632   return 0;
1633 }
1634
1635 /*!
1636  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1637  */
1638 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1639 {
1640   int sz=connI[cell1+1]-connI[cell1];
1641   if(sz==connI[cell2+1]-connI[cell2])
1642     {
1643       if(conn[connI[cell1]]==conn[connI[cell2]])
1644         {
1645           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1646           unsigned dim=cm.getDimension();
1647           if(dim!=3)
1648             {
1649               if(dim!=1)
1650                 {
1651                   int sz1=2*(sz-1);
1652                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1653                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1654                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1655                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1656                   return work!=tmp+sz1?1:0;
1657                 }
1658               else
1659                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1660             }
1661           else
1662             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1663         }
1664     }
1665   return 0;
1666 }
1667
1668 /*!
1669  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1670  */
1671 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1672 {
1673   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1674     {
1675       if(conn[connI[cell1]]==conn[connI[cell2]])
1676         {
1677           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1678           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1679           return s1==s2?1:0;
1680         }
1681     }
1682   return 0;
1683 }
1684
1685 /*!
1686  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1687  */
1688 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1689 {
1690   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1691     {
1692       std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1693       std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1694       return s1==s2?1:0;
1695     }
1696   return 0;
1697 }
1698
1699 /*!
1700  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1701  */
1702 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1703 {
1704   int sz=connI[cell1+1]-connI[cell1];
1705   if(sz==connI[cell2+1]-connI[cell2])
1706     {
1707       if(conn[connI[cell1]]==conn[connI[cell2]])
1708         {
1709           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1710           unsigned dim=cm.getDimension();
1711           if(dim!=3)
1712             {
1713               if(dim!=1)
1714                 {
1715                   int sz1=2*(sz-1);
1716                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1717                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1718                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1719                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1720                   if(work!=tmp+sz1)
1721                     return 1;
1722                   else
1723                     {
1724                       std::reverse_iterator<int *> it1((int *)tmp+sz1);
1725                       std::reverse_iterator<int *> it2((int *)tmp);
1726                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1727                         return 2;
1728                       else
1729                         return 0;
1730                     }
1731
1732                   return work!=tmp+sz1?1:0;
1733                 }
1734               else
1735                 {//case of SEG2 and SEG3
1736                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1737                     return 1;
1738                   if(!cm.isQuadratic())
1739                     {
1740                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1741                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1742                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1743                         return 2;
1744                       return 0;
1745                     }
1746                   else
1747                     {
1748                       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])
1749                         return 2;
1750                       return 0;
1751                     }
1752                 }
1753             }
1754           else
1755             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1756         }
1757     }
1758   return 0;
1759 }
1760
1761 /*!
1762  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1763  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1764  * and result remains unchanged.
1765  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1766  * If in 'candidates' pool -1 value is considered as an empty value.
1767  * WARNING this method returns only ONE set of result !
1768  */
1769 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1770 {
1771   if(candidates.size()<1)
1772     return false;
1773   bool ret=false;
1774   std::vector<int>::const_iterator iter=candidates.begin();
1775   int start=(*iter++);
1776   for(;iter!=candidates.end();iter++)
1777     {
1778       int status=AreCellsEqual(conn,connI,start,*iter,compType);
1779       if(status!=0)
1780         {
1781           if(!ret)
1782             {
1783               result->pushBackSilent(start);
1784               ret=true;
1785             }
1786           if(status==1)
1787             result->pushBackSilent(*iter);
1788           else
1789             result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1790         }
1791     }
1792   return ret;
1793 }
1794
1795 /*!
1796  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1797  * by \a compType.
1798  * This method keeps the coordiantes of \a this. This method is time consuming.
1799  *
1800  * \param [in] compType input specifying the technique used to compare cells each other.
1801  *   - 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.
1802  *   - 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)
1803  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1804  *   - 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
1805  * can be used for users not sensitive to orientation of cell
1806  * \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.
1807  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1808  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1809  * \return the correspondance array old to new in a newly allocated array.
1810  * 
1811  */
1812 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1813 {
1814   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1815   getReverseNodalConnectivity(revNodal,revNodalI);
1816   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1817 }
1818
1819 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1820                                           DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1821 {
1822   MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1823   int nbOfCells=nodalI->getNumberOfTuples()-1;
1824   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1825   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1826   const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1827   std::vector<bool> isFetched(nbOfCells,false);
1828   if(startCellId==0)
1829     {
1830       for(int i=0;i<nbOfCells;i++)
1831         {
1832           if(!isFetched[i])
1833             {
1834               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1835               std::vector<int> v,v2;
1836               if(connOfNode!=connPtr+connIPtr[i+1])
1837                 {
1838                   const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1839                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1840                   connOfNode++;
1841                 }
1842               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1843                 if(*connOfNode>=0)
1844                   {
1845                     v=v2;
1846                     const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1847                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1848                     v2.resize(std::distance(v2.begin(),it));
1849                   }
1850               if(v2.size()>1)
1851                 {
1852                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1853                     {
1854                       int pos=commonCellsI->back();
1855                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1856                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1857                         isFetched[*it]=true;
1858                     }
1859                 }
1860             }
1861         }
1862     }
1863   else
1864     {
1865       for(int i=startCellId;i<nbOfCells;i++)
1866         {
1867           if(!isFetched[i])
1868             {
1869               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1870               std::vector<int> v,v2;
1871               if(connOfNode!=connPtr+connIPtr[i+1])
1872                 {
1873                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1874                   connOfNode++;
1875                 }
1876               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1877                 if(*connOfNode>=0)
1878                   {
1879                     v=v2;
1880                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1881                     v2.resize(std::distance(v2.begin(),it));
1882                   }
1883               if(v2.size()>1)
1884                 {
1885                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1886                     {
1887                       int pos=commonCellsI->back();
1888                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1889                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1890                         isFetched[*it]=true;
1891                     }
1892                 }
1893             }
1894         }
1895     }
1896   commonCellsArr=commonCells.retn();
1897   commonCellsIArr=commonCellsI.retn();
1898 }
1899
1900 /*!
1901  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1902  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1903  * than \a this->getNumberOfCells() in the returned array means that there is no
1904  * corresponding cell in \a this mesh.
1905  * It is expected that \a this and \a other meshes share the same node coordinates
1906  * array, if it is not so an exception is thrown. 
1907  *  \param [in] other - the mesh to compare with.
1908  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1909  *         valid values [0,1,2], see zipConnectivityTraducer().
1910  *  \param [out] arr - a new instance of DataArrayInt returning correspondence
1911  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1912  *         values. The caller is to delete this array using
1913  *         decrRef() as it is no more needed.
1914  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1915  *         mesh.
1916  *
1917  *  \if ENABLE_EXAMPLES
1918  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1919  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1920  *  \endif
1921  *  \sa checkDeepEquivalOnSameNodesWith()
1922  *  \sa checkGeoEquivalWith()
1923  */
1924 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1925 {
1926   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1927   int nbOfCells=getNumberOfCells();
1928   static const int possibleCompType[]={0,1,2};
1929   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1930     {
1931       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1932       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1933       oss << " !";
1934       throw INTERP_KERNEL::Exception(oss.str().c_str());
1935     }
1936   MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1937   arr=o2n->subArray(nbOfCells);
1938   arr->setName(other->getName());
1939   int tmp;
1940   if(other->getNumberOfCells()==0)
1941     return true;
1942   return arr->getMaxValue(tmp)<nbOfCells;
1943 }
1944
1945 /*!
1946  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1947  * This method tries to determine if \b other is fully included in \b this.
1948  * The main difference is that this method is not expected to throw exception.
1949  * This method has two outputs :
1950  *
1951  * \param other other mesh
1952  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1953  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1954  */
1955 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1956 {
1957   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1958   DataArrayInt *commonCells=0,*commonCellsI=0;
1959   int thisNbCells=getNumberOfCells();
1960   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1961   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1962   const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1963   int otherNbCells=other->getNumberOfCells();
1964   MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1965   arr2->alloc(otherNbCells,1);
1966   arr2->fillWithZero();
1967   int *arr2Ptr=arr2->getPointer();
1968   int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1969   for(int i=0;i<nbOfCommon;i++)
1970     {
1971       int start=commonCellsPtr[commonCellsIPtr[i]];
1972       if(start<thisNbCells)
1973         {
1974           for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1975             {
1976               int sig=commonCellsPtr[j]>0?1:-1;
1977               int val=std::abs(commonCellsPtr[j])-1;
1978               if(val>=thisNbCells)
1979                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1980             }
1981         }
1982     }
1983   arr2->setName(other->getName());
1984   if(arr2->presenceOfValue(0))
1985     return false;
1986   arr=arr2.retn();
1987   return true;
1988 }
1989
1990 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1991 {
1992   if(!other)
1993     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1994   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1995   if(!otherC)
1996     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1997   std::vector<const MEDCouplingUMesh *> ms(2);
1998   ms[0]=this;
1999   ms[1]=otherC;
2000   return MergeUMeshesOnSameCoords(ms);
2001 }
2002
2003 /*!
2004  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2005  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2006  * cellIds is not given explicitely but by a range python like.
2007  * 
2008  * \param start
2009  * \param end
2010  * \param step
2011  * \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.
2012  * \return a newly allocated
2013  * 
2014  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2015  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2016  */
2017 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2018 {
2019   if(getMeshDimension()!=-1)
2020     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2021   else
2022     {
2023       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2024       if(newNbOfCells!=1)
2025         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2026       if(start!=0)
2027         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2028       incrRef();
2029       return const_cast<MEDCouplingUMesh *>(this);
2030     }
2031 }
2032
2033 /*!
2034  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2035  * The result mesh shares or not the node coordinates array with \a this mesh depending
2036  * on \a keepCoords parameter.
2037  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2038  *           to write this mesh to the MED file, its cells must be sorted using
2039  *           sortCellsInMEDFileFrmt().
2040  *  \param [in] begin - an array of cell ids to include to the new mesh.
2041  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2042  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2043  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2044  *         by calling zipCoords().
2045  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2046  *         to delete this mesh using decrRef() as it is no more needed. 
2047  *  \throw If the coordinates array is not set.
2048  *  \throw If the nodal connectivity of cells is not defined.
2049  *  \throw If any cell id in the array \a begin is not valid.
2050  *
2051  *  \if ENABLE_EXAMPLES
2052  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2053  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2054  *  \endif
2055  */
2056 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2057 {
2058   if(getMeshDimension()!=-1)
2059     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2060   else
2061     {
2062       if(end-begin!=1)
2063         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2064       if(begin[0]!=0)
2065         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2066       incrRef();
2067       return const_cast<MEDCouplingUMesh *>(this);
2068     }
2069 }
2070
2071 /*!
2072  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2073  *
2074  * 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.
2075  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2076  * The number of cells of \b this will remain the same with this method.
2077  *
2078  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2079  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2080  * \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 ).
2081  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2082  */
2083 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2084 {
2085   checkConnectivityFullyDefined();
2086   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2087   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2088     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2089   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2090     {
2091       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2092       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2093       throw INTERP_KERNEL::Exception(oss.str().c_str());
2094     }
2095   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2096   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2097     {
2098       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2099       throw INTERP_KERNEL::Exception(oss.str().c_str());
2100     }
2101   int nbOfCells=getNumberOfCells();
2102   bool easyAssign=true;
2103   const int *connI=_nodal_connec_index->getConstPointer();
2104   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2105   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2106     {
2107       if(*it>=0 && *it<nbOfCells)
2108         {
2109           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2110         }
2111       else
2112         {
2113           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2114           throw INTERP_KERNEL::Exception(oss.str().c_str());
2115         }
2116     }
2117   if(easyAssign)
2118     {
2119       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2120       computeTypes();
2121     }
2122   else
2123     {
2124       DataArrayInt *arrOut=0,*arrIOut=0;
2125       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2126                                                arrOut,arrIOut);
2127       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2128       setConnectivity(arrOut,arrIOut,true);
2129     }
2130 }
2131
2132 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2133 {
2134   checkConnectivityFullyDefined();
2135   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2136   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2137     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2138   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2139     {
2140       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2141       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2142       throw INTERP_KERNEL::Exception(oss.str().c_str());
2143     }
2144   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2145   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2146     {
2147       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2148       throw INTERP_KERNEL::Exception(oss.str().c_str());
2149     }
2150   int nbOfCells=getNumberOfCells();
2151   bool easyAssign=true;
2152   const int *connI=_nodal_connec_index->getConstPointer();
2153   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2154   int it=start;
2155   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2156     {
2157       if(it>=0 && it<nbOfCells)
2158         {
2159           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2160         }
2161       else
2162         {
2163           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2164           throw INTERP_KERNEL::Exception(oss.str().c_str());
2165         }
2166     }
2167   if(easyAssign)
2168     {
2169       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2170       computeTypes();
2171     }
2172   else
2173     {
2174       DataArrayInt *arrOut=0,*arrIOut=0;
2175       MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2176                                                 arrOut,arrIOut);
2177       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2178       setConnectivity(arrOut,arrIOut,true);
2179     }
2180 }                      
2181
2182 /*!
2183  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2184  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2185  * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2186  * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2187  *
2188  * \param [in] begin input start of array of node ids.
2189  * \param [in] end input end of array of node ids.
2190  * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2191  * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2192  */
2193 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2194 {
2195   MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2196   checkConnectivityFullyDefined();
2197   int tmp=-1;
2198   int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2199   std::vector<bool> fastFinder(sz,false);
2200   for(const int *work=begin;work!=end;work++)
2201     if(*work>=0 && *work<sz)
2202       fastFinder[*work]=true;
2203   int nbOfCells=getNumberOfCells();
2204   const int *conn=getNodalConnectivity()->getConstPointer();
2205   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2206   for(int i=0;i<nbOfCells;i++)
2207     {
2208       int ref=0,nbOfHit=0;
2209       for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2210         if(*work2>=0)
2211           {
2212             ref++;
2213             if(fastFinder[*work2])
2214               nbOfHit++;
2215           }
2216       if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2217         cellIdsKept->pushBackSilent(i);
2218     }
2219   cellIdsKeptArr=cellIdsKept.retn();
2220 }
2221
2222 /*!
2223  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2224  * this->getMeshDimension(), that bound some cells of \a this mesh.
2225  * The cells of lower dimension to include to the result mesh are selected basing on
2226  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2227  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2228  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2229  * created mesh shares the node coordinates array with \a this mesh. 
2230  *  \param [in] begin - the array of node ids.
2231  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2232  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2233  *         array \a begin are added, else cells whose any node is in the
2234  *         array \a begin are added.
2235  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2236  *         to delete this mesh using decrRef() as it is no more needed. 
2237  *  \throw If the coordinates array is not set.
2238  *  \throw If the nodal connectivity of cells is not defined.
2239  *  \throw If any node id in \a begin is not valid.
2240  *
2241  *  \if ENABLE_EXAMPLES
2242  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2243  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2244  *  \endif
2245  */
2246 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2247 {
2248   MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2249   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2250   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2251   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2252   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2253 }
2254
2255 /*!
2256  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2257  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2258  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2259  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2260  *         by calling zipCoords().
2261  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2262  *         to delete this mesh using decrRef() as it is no more needed. 
2263  *  \throw If the coordinates array is not set.
2264  *  \throw If the nodal connectivity of cells is not defined.
2265  *
2266  *  \if ENABLE_EXAMPLES
2267  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2268  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2269  *  \endif
2270  */
2271 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2272 {
2273   DataArrayInt *desc=DataArrayInt::New();
2274   DataArrayInt *descIndx=DataArrayInt::New();
2275   DataArrayInt *revDesc=DataArrayInt::New();
2276   DataArrayInt *revDescIndx=DataArrayInt::New();
2277   //
2278   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2279   revDesc->decrRef();
2280   desc->decrRef();
2281   descIndx->decrRef();
2282   int nbOfCells=meshDM1->getNumberOfCells();
2283   const int *revDescIndxC=revDescIndx->getConstPointer();
2284   std::vector<int> boundaryCells;
2285   for(int i=0;i<nbOfCells;i++)
2286     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2287       boundaryCells.push_back(i);
2288   revDescIndx->decrRef();
2289   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2290   return ret;
2291 }
2292
2293 /*!
2294  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2295  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2296  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown. 
2297  */
2298 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2299 {
2300   checkFullyDefined();
2301   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2302   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2303   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2304   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2305   //
2306   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2307   desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2308   //
2309   MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2310   MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2311   const int *revDescPtr=revDesc->getConstPointer();
2312   const int *revDescIndxPtr=revDescIndx->getConstPointer();
2313   int nbOfCells=getNumberOfCells();
2314   std::vector<bool> ret1(nbOfCells,false);
2315   int sz=0;
2316   for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2317     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2318       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2319   //
2320   DataArrayInt *ret2=DataArrayInt::New();
2321   ret2->alloc(sz,1);
2322   int *ret2Ptr=ret2->getPointer();
2323   sz=0;
2324   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2325     if(*it)
2326       *ret2Ptr++=sz;
2327   ret2->setName("BoundaryCells");
2328   return ret2;
2329 }
2330
2331 /*!
2332  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2333  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2334  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2335  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2336  *
2337  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2338  * 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
2339  * equals a cell in \b otherDimM1OnSameCoords.
2340  *
2341  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2342  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2343  *
2344  * \param [in] otherDimM1OnSameCoords
2345  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2346  * \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
2347  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2348  */
2349 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2350 {
2351   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2352     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2353   checkConnectivityFullyDefined();
2354   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2355   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2356     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2357   MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2358   MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2359   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2360   MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2361   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2362   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2363   DataArrayInt *idsOtherInConsti=0;
2364   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2365   MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2366   if(!b)
2367     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2368   std::set<int> s1;
2369   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2370     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2371   MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2372   s1arr_renum1->sort();
2373   cellIdsRk0=s0arr.retn();
2374   //cellIdsRk1=s_renum1.retn();
2375   cellIdsRk1=s1arr_renum1.retn();
2376 }
2377
2378 /*!
2379  * 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
2380  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2381  * 
2382  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2383  */
2384 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2385 {
2386   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2387   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2388   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2389   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2390   //
2391   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2392   revDesc=0; desc=0; descIndx=0;
2393   MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2394   MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2395   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2396 }
2397
2398 /*!
2399  * Finds nodes lying on the boundary of \a this mesh.
2400  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2401  *          nodes. The caller is to delete this array using decrRef() as it is no
2402  *          more needed.
2403  *  \throw If the coordinates array is not set.
2404  *  \throw If the nodal connectivity of cells is node defined.
2405  *
2406  *  \if ENABLE_EXAMPLES
2407  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2408  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2409  *  \endif
2410  */
2411 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2412 {
2413   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2414   return skin->computeFetchedNodeIds();
2415 }
2416
2417 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2418 {
2419   incrRef();
2420   return const_cast<MEDCouplingUMesh *>(this);
2421 }
2422
2423 /*!
2424  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2425  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2426  * 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.
2427  * If a node is in the boundary of \b this \b and in the boundary of \b otherDimM1OnSameCoords this node is considerd as needed to be duplicated.
2428  * 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.
2429  *
2430  * \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
2431  *             parameter is altered during the call.
2432  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2433  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2434  * \param [out] cellIdsNotModified cell ids int \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.
2435  *
2436  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2437  */
2438 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2439                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2440 {
2441   typedef MCAuto<DataArrayInt> DAInt;
2442   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2443
2444   checkFullyDefined();
2445   otherDimM1OnSameCoords.checkFullyDefined();
2446   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2447     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2448   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2449     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2450
2451   // Checking star-shaped M1 group:
2452   DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2453   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2454   DAInt dsi = rdit0->deltaShiftIndex();
2455   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2456   if(idsTmp0->getNumberOfTuples())
2457     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2458   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2459
2460   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2461   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2462   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2463   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2464   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2465   dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2466   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2467   dsi = rdit0->deltaShiftIndex();
2468   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2469   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2470   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2471   // In 3D, some points on the boundary of M0 still need duplication:
2472   DAInt notDup = 0;
2473   if (getMeshDimension() == 3)
2474     {
2475       DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2476       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2477       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2478       DataArrayInt * corresp=0;
2479       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2480       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2481       corresp->decrRef();
2482       if (validIds->getNumberOfTuples())
2483         {
2484           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2485           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2486           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2487           notDup = xtrem->buildSubstraction(fNodes1);
2488         }
2489       else
2490         notDup = xtrem->buildSubstraction(fNodes);
2491     }
2492   else
2493     notDup = xtrem->buildSubstraction(fNodes);
2494
2495   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2496   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2497   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2498   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2499
2500   //
2501   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2502   int nCells2 = m0Part2->getNumberOfCells();
2503   DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2504   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2505
2506   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2507   DataArrayInt *tmp00=0,*tmp11=0;
2508   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2509   DAInt neighInit00(tmp00);
2510   DAInt neighIInit00(tmp11);
2511   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2512   DataArrayInt *idsTmp=0;
2513   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2514   DAInt ids(idsTmp);
2515   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2516   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2517   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2518   DataArrayInt *tmp0=0,*tmp1=0;
2519   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2520   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2521   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2522   DAInt neigh00(tmp0);
2523   DAInt neighI00(tmp1);
2524
2525   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2526   int seed = 0, nIter = 0;
2527   int nIterMax = nCells2+1; // Safety net for the loop
2528   DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2529   hitCells->fillWithValue(-1);
2530   DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2531   cellsToModifyConn0_torenum->alloc(0,1);
2532   while (nIter < nIterMax)
2533     {
2534       DAInt t = hitCells->findIdsEqual(-1);
2535       if (!t->getNumberOfTuples())
2536         break;
2537       // Connex zone without the crack (to compute the next seed really)
2538       int dnu;
2539       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2540       int cnt = 0;
2541       for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2542         hitCells->setIJ(*ptr,0,1);
2543       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2544       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2545       cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2546       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2547       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2548       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2549       DAInt intersec = nonHitCells->buildIntersection(comple);
2550       if (intersec->getNumberOfTuples())
2551         { seed = intersec->getIJ(0,0); }
2552       else
2553         { break; }
2554       nIter++;
2555     }
2556   if (nIter >= nIterMax)
2557     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2558
2559   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2560   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2561   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2562   //
2563   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2564   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2565   nodeIdsToDuplicate=dupl.retn();
2566 }
2567
2568 /*!
2569  * This method operates a modification of the connectivity and coords in \b this.
2570  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2571  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2572  * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2573  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2574  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2575  * 
2576  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2577  * 
2578  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2579  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2580  */
2581 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2582 {
2583   int nbOfNodes=getNumberOfNodes();
2584   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2585   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2586 }
2587
2588 /*!
2589  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2590  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2591  *
2592  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2593  *
2594  * \sa renumberNodesInConn
2595  */
2596 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2597 {
2598   checkConnectivityFullyDefined();
2599   int *conn(getNodalConnectivity()->getPointer());
2600   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2601   int nbOfCells(getNumberOfCells());
2602   for(int i=0;i<nbOfCells;i++)
2603     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2604       {
2605         int& node=conn[iconn];
2606         if(node>=0)//avoid polyhedron separator
2607           {
2608             node+=offset;
2609           }
2610       }
2611   _nodal_connec->declareAsNew();
2612   updateTime();
2613 }
2614
2615 /*!
2616  *  Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2617  *  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
2618  *  of a big mesh.
2619  */
2620 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2621 {
2622   checkConnectivityFullyDefined();
2623   int *conn(getNodalConnectivity()->getPointer());
2624   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2625   int nbOfCells(getNumberOfCells());
2626   for(int i=0;i<nbOfCells;i++)
2627     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2628       {
2629         int& node=conn[iconn];
2630         if(node>=0)//avoid polyhedron separator
2631           {
2632             INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2633             if(it!=newNodeNumbersO2N.end())
2634               {
2635                 node=(*it).second;
2636               }
2637             else
2638               {
2639                 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2640                 throw INTERP_KERNEL::Exception(oss.str().c_str());
2641               }
2642           }
2643       }
2644   _nodal_connec->declareAsNew();
2645   updateTime();
2646 }
2647
2648 /*!
2649  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2650  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2651  * This method is a generalization of shiftNodeNumbersInConn().
2652  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2653  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2654  *         this->getNumberOfNodes(), in "Old to New" mode. 
2655  *         See \ref numbering for more info on renumbering modes.
2656  *  \throw If the nodal connectivity of cells is not defined.
2657  *
2658  *  \if ENABLE_EXAMPLES
2659  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2660  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2661  *  \endif
2662  */
2663 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2664 {
2665   checkConnectivityFullyDefined();
2666   int *conn=getNodalConnectivity()->getPointer();
2667   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2668   int nbOfCells(getNumberOfCells());
2669   for(int i=0;i<nbOfCells;i++)
2670     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2671       {
2672         int& node=conn[iconn];
2673         if(node>=0)//avoid polyhedron separator
2674           {
2675             node=newNodeNumbersO2N[node];
2676           }
2677       }
2678   _nodal_connec->declareAsNew();
2679   updateTime();
2680 }
2681
2682 /*!
2683  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2684  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2685  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2686  * 
2687  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2688  */
2689 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2690 {
2691   checkConnectivityFullyDefined();
2692   int *conn=getNodalConnectivity()->getPointer();
2693   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2694   int nbOfCells=getNumberOfCells();
2695   for(int i=0;i<nbOfCells;i++)
2696     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2697       {
2698         int& node=conn[iconn];
2699         if(node>=0)//avoid polyhedron separator
2700           {
2701             node+=delta;
2702           }
2703       }
2704   _nodal_connec->declareAsNew();
2705   updateTime();
2706 }
2707
2708 /*!
2709  * This method operates a modification of the connectivity in \b this.
2710  * 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.
2711  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2712  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2713  * More explicitely the renumber array in nodes is not explicitely given in old2new to avoid to build a big array of renumbering whereas typically few node ids needs to be
2714  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2715  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2716  * 
2717  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2718  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2719  * 
2720  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2721  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2722  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ). 
2723  */
2724 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2725 {
2726   checkConnectivityFullyDefined();
2727   std::map<int,int> m;
2728   int val=offset;
2729   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2730     m[*work]=val;
2731   int *conn=getNodalConnectivity()->getPointer();
2732   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2733   int nbOfCells=getNumberOfCells();
2734   for(int i=0;i<nbOfCells;i++)
2735     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2736       {
2737         int& node=conn[iconn];
2738         if(node>=0)//avoid polyhedron separator
2739           {
2740             std::map<int,int>::iterator it=m.find(node);
2741             if(it!=m.end())
2742               node=(*it).second;
2743           }
2744       }
2745   updateTime();
2746 }
2747
2748 /*!
2749  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2750  *
2751  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2752  * After the call of this method the number of cells remains the same as before.
2753  *
2754  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2755  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2756  * be strictly in [0;this->getNumberOfCells()).
2757  *
2758  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2759  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2760  * should be contained in[0;this->getNumberOfCells()).
2761  * 
2762  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2763  * \param check
2764  */
2765 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2766 {
2767   checkConnectivityFullyDefined();
2768   int nbCells=getNumberOfCells();
2769   const int *array=old2NewBg;
2770   if(check)
2771     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2772   //
2773   const int *conn=_nodal_connec->getConstPointer();
2774   const int *connI=_nodal_connec_index->getConstPointer();
2775   MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2776   MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2777   const int *n2oPtr=n2o->begin();
2778   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2779   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2780   newConn->copyStringInfoFrom(*_nodal_connec);
2781   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2782   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2783   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2784   //
2785   int *newC=newConn->getPointer();
2786   int *newCI=newConnI->getPointer();
2787   int loc=0;
2788   newCI[0]=loc;
2789   for(int i=0;i<nbCells;i++)
2790     {
2791       int pos=n2oPtr[i];
2792       int nbOfElts=connI[pos+1]-connI[pos];
2793       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2794       loc+=nbOfElts;
2795       newCI[i+1]=loc;
2796     }
2797   //
2798   setConnectivity(newConn,newConnI);
2799   if(check)
2800     free(const_cast<int *>(array));
2801 }
2802
2803 /*!
2804  * Finds cells whose bounding boxes intersect a given bounding box.
2805  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2806  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2807  *         zMax (if in 3D). 
2808  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2809  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2810  *         extent of the bounding box of cell to produce an addition to this bounding box.
2811  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2812  *         cells. The caller is to delete this array using decrRef() as it is no more
2813  *         needed. 
2814  *  \throw If the coordinates array is not set.
2815  *  \throw If the nodal connectivity of cells is not defined.
2816  *
2817  *  \if ENABLE_EXAMPLES
2818  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2819  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2820  *  \endif
2821  */
2822 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2823 {
2824   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2825   if(getMeshDimension()==-1)
2826     {
2827       elems->pushBackSilent(0);
2828       return elems.retn();
2829     }
2830   int dim=getSpaceDimension();
2831   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2832   const int* conn      = getNodalConnectivity()->getConstPointer();
2833   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2834   const double* coords = getCoords()->getConstPointer();
2835   int nbOfCells=getNumberOfCells();
2836   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2837     {
2838       for (int i=0; i<dim; i++)
2839         {
2840           elem_bb[i*2]=std::numeric_limits<double>::max();
2841           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2842         }
2843
2844       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2845         {
2846           int node= conn[inode];
2847           if(node>=0)//avoid polyhedron separator
2848             {
2849               for (int idim=0; idim<dim; idim++)
2850                 {
2851                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2852                     {
2853                       elem_bb[idim*2] = coords[node*dim+idim] ;
2854                     }
2855                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2856                     {
2857                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2858                     }
2859                 }
2860             }
2861         }
2862       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2863         elems->pushBackSilent(ielem);
2864     }
2865   return elems.retn();
2866 }
2867
2868 /*!
2869  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2870  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2871  * added in 'elems' parameter.
2872  */
2873 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2874 {
2875   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2876   if(getMeshDimension()==-1)
2877     {
2878       elems->pushBackSilent(0);
2879       return elems.retn();
2880     }
2881   int dim=getSpaceDimension();
2882   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2883   const int* conn      = getNodalConnectivity()->getConstPointer();
2884   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2885   const double* coords = getCoords()->getConstPointer();
2886   int nbOfCells=getNumberOfCells();
2887   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2888     {
2889       for (int i=0; i<dim; i++)
2890         {
2891           elem_bb[i*2]=std::numeric_limits<double>::max();
2892           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2893         }
2894
2895       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2896         {
2897           int node= conn[inode];
2898           if(node>=0)//avoid polyhedron separator
2899             {
2900               for (int idim=0; idim<dim; idim++)
2901                 {
2902                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2903                     {
2904                       elem_bb[idim*2] = coords[node*dim+idim] ;
2905                     }
2906                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2907                     {
2908                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2909                     }
2910                 }
2911             }
2912         }
2913       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2914         elems->pushBackSilent(ielem);
2915     }
2916   return elems.retn();
2917 }
2918
2919 /*!
2920  * Returns a type of a cell by its id.
2921  *  \param [in] cellId - the id of the cell of interest.
2922  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2923  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2924  */
2925 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2926 {
2927   const int *ptI=_nodal_connec_index->getConstPointer();
2928   const int *pt=_nodal_connec->getConstPointer();
2929   if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2930     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2931   else
2932     {
2933       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2934       throw INTERP_KERNEL::Exception(oss.str().c_str());
2935     }
2936 }
2937
2938 /*!
2939  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2940  * This method does not throw exception if geometric type \a type is not in \a this.
2941  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2942  * The coordinates array is not considered here.
2943  *
2944  * \param [in] type the geometric type
2945  * \return cell ids in this having geometric type \a type.
2946  */
2947 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2948 {
2949
2950   MCAuto<DataArrayInt> ret=DataArrayInt::New();
2951   ret->alloc(0,1);
2952   checkConnectivityFullyDefined();
2953   int nbCells=getNumberOfCells();
2954   int mdim=getMeshDimension();
2955   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2956   if(mdim!=(int)cm.getDimension())
2957     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2958   const int *ptI=_nodal_connec_index->getConstPointer();
2959   const int *pt=_nodal_connec->getConstPointer();
2960   for(int i=0;i<nbCells;i++)
2961     {
2962       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2963         ret->pushBackSilent(i);
2964     }
2965   return ret.retn();
2966 }
2967
2968 /*!
2969  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2970  */
2971 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2972 {
2973   const int *ptI=_nodal_connec_index->getConstPointer();
2974   const int *pt=_nodal_connec->getConstPointer();
2975   int nbOfCells=getNumberOfCells();
2976   int ret=0;
2977   for(int i=0;i<nbOfCells;i++)
2978     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2979       ret++;
2980   return ret;
2981 }
2982
2983 /*!
2984  * Returns the nodal connectivity of a given cell.
2985  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2986  * all returned node ids can be used in getCoordinatesOfNode().
2987  *  \param [in] cellId - an id of the cell of interest.
2988  *  \param [in,out] conn - a vector where the node ids are appended. It is not
2989  *         cleared before the appending.
2990  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2991  */
2992 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2993 {
2994   const int *ptI=_nodal_connec_index->getConstPointer();
2995   const int *pt=_nodal_connec->getConstPointer();
2996   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2997     if(*w>=0)
2998       conn.push_back(*w);
2999 }
3000
3001 std::string MEDCouplingUMesh::simpleRepr() const
3002 {
3003   static const char msg0[]="No coordinates specified !";
3004   std::ostringstream ret;
3005   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3006   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3007   int tmpp1,tmpp2;
3008   double tt=getTime(tmpp1,tmpp2);
3009   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3010   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3011   if(_mesh_dim>=-1)
3012     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3013   else
3014     { ret << " Mesh dimension has not been set or is invalid !"; }
3015   if(_coords!=0)
3016     {
3017       const int spaceDim=getSpaceDimension();
3018       ret << spaceDim << "\nInfo attached on space dimension : ";
3019       for(int i=0;i<spaceDim;i++)
3020         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3021       ret << "\n";
3022     }
3023   else
3024     ret << msg0 << "\n";
3025   ret << "Number of nodes : ";
3026   if(_coords!=0)
3027     ret << getNumberOfNodes() << "\n";
3028   else
3029     ret << msg0 << "\n";
3030   ret << "Number of cells : ";
3031   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3032     ret << getNumberOfCells() << "\n";
3033   else
3034     ret << "No connectivity specified !" << "\n";
3035   ret << "Cell types present : ";
3036   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3037     {
3038       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3039       ret << cm.getRepr() << " ";
3040     }
3041   ret << "\n";
3042   return ret.str();
3043 }
3044
3045 std::string MEDCouplingUMesh::advancedRepr() const
3046 {
3047   std::ostringstream ret;
3048   ret << simpleRepr();
3049   ret << "\nCoordinates array : \n___________________\n\n";
3050   if(_coords)
3051     _coords->reprWithoutNameStream(ret);
3052   else
3053     ret << "No array set !\n";
3054   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3055   reprConnectivityOfThisLL(ret);
3056   return ret.str();
3057 }
3058
3059 /*!
3060  * This method returns a C++ code that is a dump of \a this.
3061  * This method will throw if this is not fully defined.
3062  */
3063 std::string MEDCouplingUMesh::cppRepr() const
3064 {
3065   static const char coordsName[]="coords";
3066   static const char connName[]="conn";
3067   static const char connIName[]="connI";
3068   checkFullyDefined();
3069   std::ostringstream ret; ret << "// coordinates" << std::endl;
3070   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3071   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3072   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3073   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3074   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3075   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3076   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3077   return ret.str();
3078 }
3079
3080 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3081 {
3082   std::ostringstream ret;
3083   reprConnectivityOfThisLL(ret);
3084   return ret.str();
3085 }
3086
3087 /*!
3088  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3089  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3090  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3091  * some algos).
3092  * 
3093  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3094  * 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
3095  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3096  */
3097 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3098 {
3099   int mdim=getMeshDimension();
3100   if(mdim<0)
3101     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3102   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3103   MCAuto<DataArrayInt> tmp1,tmp2;
3104   bool needToCpyCT=true;
3105   if(!_nodal_connec)
3106     {
3107       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3108       needToCpyCT=false;
3109     }
3110   else
3111     {
3112       tmp1=_nodal_connec;
3113       tmp1->incrRef();
3114     }
3115   if(!_nodal_connec_index)
3116     {
3117       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3118       needToCpyCT=false;
3119     }
3120   else
3121     {
3122       tmp2=_nodal_connec_index;
3123       tmp2->incrRef();
3124     }
3125   ret->setConnectivity(tmp1,tmp2,false);
3126   if(needToCpyCT)
3127     ret->_types=_types;
3128   if(!_coords)
3129     {
3130       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3131       ret->setCoords(coords);
3132     }
3133   else
3134     ret->setCoords(_coords);
3135   return ret.retn();
3136 }
3137
3138 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3139 {
3140   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3141     {
3142       int nbOfCells=getNumberOfCells();
3143       const int *c=_nodal_connec->getConstPointer();
3144       const int *ci=_nodal_connec_index->getConstPointer();
3145       for(int i=0;i<nbOfCells;i++)
3146         {
3147           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3148           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3149           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3150           stream << "\n";
3151         }
3152     }
3153   else
3154     stream << "Connectivity not defined !\n";
3155 }
3156
3157 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3158 {
3159   const int *ptI=_nodal_connec_index->getConstPointer();
3160   const int *pt=_nodal_connec->getConstPointer();
3161   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3162     return ptI[cellId+1]-ptI[cellId]-1;
3163   else
3164     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3165 }
3166
3167 /*!
3168  * Returns types of cells of the specified part of \a this mesh.
3169  * This method avoids computing sub-mesh explicitely to get its types.
3170  *  \param [in] begin - an array of cell ids of interest.
3171  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3172  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3173  *         describing the cell types. 
3174  *  \throw If the coordinates array is not set.
3175  *  \throw If the nodal connectivity of cells is not defined.
3176  *  \sa getAllGeoTypes()
3177  */
3178 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3179 {
3180   checkFullyDefined();
3181   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3182   const int *conn=_nodal_connec->getConstPointer();
3183   const int *connIndex=_nodal_connec_index->getConstPointer();
3184   for(const int *w=begin;w!=end;w++)
3185     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3186   return ret;
3187 }
3188
3189 /*!
3190  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3191  * Optionally updates
3192  * a set of types of cells constituting \a this mesh. 
3193  * This method is for advanced users having prepared their connectivity before. For
3194  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3195  *  \param [in] conn - the nodal connectivity array. 
3196  *  \param [in] connIndex - the nodal connectivity index array.
3197  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3198  *         mesh is updated.
3199  */
3200 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3201 {
3202   DataArrayInt::SetArrayIn(conn,_nodal_connec);
3203   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3204   if(isComputingTypes)
3205     computeTypes();
3206   declareAsNew();
3207 }
3208
3209 /*!
3210  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3211  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3212  */
3213 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3214     _nodal_connec(0),_nodal_connec_index(0),
3215     _types(other._types)
3216 {
3217   if(other._nodal_connec)
3218     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3219   if(other._nodal_connec_index)
3220     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3221 }
3222
3223 MEDCouplingUMesh::~MEDCouplingUMesh()
3224 {
3225   if(_nodal_connec)
3226     _nodal_connec->decrRef();
3227   if(_nodal_connec_index)
3228     _nodal_connec_index->decrRef();
3229 }
3230
3231 /*!
3232  * Recomputes a set of cell types of \a this mesh. For more info see
3233  * \ref MEDCouplingUMeshNodalConnectivity.
3234  */
3235 void MEDCouplingUMesh::computeTypes()
3236 {
3237   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3238 }
3239
3240 /*!
3241  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3242  */
3243 void MEDCouplingUMesh::checkFullyDefined() const
3244 {
3245   if(!_nodal_connec_index || !_nodal_connec || !_coords)
3246     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3247 }
3248
3249 /*!
3250  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3251  */
3252 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3253 {
3254   if(!_nodal_connec_index || !_nodal_connec)
3255     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3256 }
3257
3258 /*!
3259  * Returns a number of cells constituting \a this mesh. 
3260  *  \return int - the number of cells in \a this mesh.
3261  *  \throw If the nodal connectivity of cells is not defined.
3262  */
3263 int MEDCouplingUMesh::getNumberOfCells() const
3264
3265   if(_nodal_connec_index)
3266     return _nodal_connec_index->getNumberOfTuples()-1;
3267   else
3268     if(_mesh_dim==-1)
3269       return 1;
3270     else
3271       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3272 }
3273
3274 /*!
3275  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3276  * mesh. For more info see \ref meshes.
3277  *  \return int - the dimension of \a this mesh.
3278  *  \throw If the mesh dimension is not defined using setMeshDimension().
3279  */
3280 int MEDCouplingUMesh::getMeshDimension() const
3281 {
3282   if(_mesh_dim<-1)
3283     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3284   return _mesh_dim;
3285 }
3286
3287 /*!
3288  * Returns a length of the nodal connectivity array.
3289  * This method is for test reason. Normally the integer returned is not useable by
3290  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3291  *  \return int - the length of the nodal connectivity array.
3292  */
3293 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3294 {
3295   return _nodal_connec->getNbOfElems();
3296 }
3297
3298 /*!
3299  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3300  */
3301 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3302 {
3303   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3304   tinyInfo.push_back(getMeshDimension());
3305   tinyInfo.push_back(getNumberOfCells());
3306   if(_nodal_connec)
3307     tinyInfo.push_back(getNodalConnectivityArrayLen());
3308   else
3309     tinyInfo.push_back(-1);
3310 }
3311
3312 /*!
3313  * First step of unserialization process.
3314  */
3315 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3316 {
3317   return tinyInfo[6]<=0;
3318 }
3319
3320 /*!
3321  * Second step of serialization process.
3322  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3323  * \param a1
3324  * \param a2
3325  * \param littleStrings
3326  */
3327 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3328 {
3329   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3330   if(tinyInfo[5]!=-1)
3331     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3332 }
3333
3334 /*!
3335  * Third and final step of serialization process.
3336  */
3337 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3338 {
3339   MEDCouplingPointSet::serialize(a1,a2);
3340   if(getMeshDimension()>-1)
3341     {
3342       a1=DataArrayInt::New();
3343       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3344       int *ptA1=a1->getPointer();
3345       const int *conn=getNodalConnectivity()->getConstPointer();
3346       const int *index=getNodalConnectivityIndex()->getConstPointer();
3347       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3348       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3349     }
3350   else
3351     a1=0;
3352 }
3353
3354 /*!
3355  * Second and final unserialization process.
3356  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3357  */
3358 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3359 {
3360   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3361   setMeshDimension(tinyInfo[5]);
3362   if(tinyInfo[7]!=-1)
3363     {
3364       // Connectivity
3365       const int *recvBuffer=a1->getConstPointer();
3366       MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3367       myConnecIndex->alloc(tinyInfo[6]+1,1);
3368       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3369       MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3370       myConnec->alloc(tinyInfo[7],1);
3371       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3372       setConnectivity(myConnec, myConnecIndex);
3373     }
3374 }
3375
3376 /*!
3377  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3378  * CellIds are given using range specified by a start an end and step.
3379  */
3380 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3381 {
3382   checkFullyDefined();
3383   int ncell=getNumberOfCells();
3384   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3385   ret->_mesh_dim=_mesh_dim;
3386   ret->setCoords(_coords);
3387   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3388   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3389   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3390   int work=start;
3391   const int *conn=_nodal_connec->getConstPointer();
3392   const int *connIndex=_nodal_connec_index->getConstPointer();
3393   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3394     {
3395       if(work>=0 && work<ncell)
3396         {
3397           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3398         }
3399       else
3400         {
3401           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3402           throw INTERP_KERNEL::Exception(oss.str().c_str());
3403         }
3404     }
3405   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3406   int *newConnPtr=newConn->getPointer();
3407   std::set<INTERP_KERNEL::NormalizedCellType> types;
3408   work=start;
3409   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3410     {
3411       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3412       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3413     }
3414   ret->setConnectivity(newConn,newConnI,false);
3415   ret->_types=types;
3416   ret->copyTinyInfoFrom(this);
3417   return ret.retn();
3418 }
3419
3420 /*!
3421  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3422  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3423  * The return newly allocated mesh will share the same coordinates as \a this.
3424  */
3425 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3426 {
3427   checkConnectivityFullyDefined();
3428   int ncell=getNumberOfCells();
3429   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3430   ret->_mesh_dim=_mesh_dim;
3431   ret->setCoords(_coords);
3432   std::size_t nbOfElemsRet=std::distance(begin,end);
3433   int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3434   connIndexRet[0]=0;
3435   const int *conn=_nodal_connec->getConstPointer();
3436   const int *connIndex=_nodal_connec_index->getConstPointer();
3437   int newNbring=0;
3438   for(const int *work=begin;work!=end;work++,newNbring++)
3439     {
3440       if(*work>=0 && *work<ncell)
3441         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3442       else
3443         {
3444           free(connIndexRet);
3445           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3446           throw INTERP_KERNEL::Exception(oss.str().c_str());
3447         }
3448     }
3449   int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3450   int *connRetWork=connRet;
3451   std::set<INTERP_KERNEL::NormalizedCellType> types;
3452   for(const int *work=begin;work!=end;work++)
3453     {
3454       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3455       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3456     }
3457   MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3458   connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3459   MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3460   connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3461   ret->setConnectivity(connRetArr,connIndexRetArr,false);
3462   ret->_types=types;
3463   ret->copyTinyInfoFrom(this);
3464   return ret.retn();
3465 }
3466
3467 /*!
3468  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3469  * mesh.<br>
3470  * For 1D cells, the returned field contains lengths.<br>
3471  * For 2D cells, the returned field contains areas.<br>
3472  * For 3D cells, the returned field contains volumes.
3473  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3474  *         orientation, i.e. the volume is always positive.
3475  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3476  *         and one time . The caller is to delete this field using decrRef() as it is no
3477  *         more needed.
3478  */
3479 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3480 {
3481   std::string name="MeasureOfMesh_";
3482   name+=getName();
3483   int nbelem=getNumberOfCells();
3484   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3485   field->setName(name);
3486   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3487   array->alloc(nbelem,1);
3488   double *area_vol=array->getPointer();
3489   field->setArray(array) ; array=0;
3490   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3491   field->synchronizeTimeWithMesh();
3492   if(getMeshDimension()!=-1)
3493     {
3494       int ipt;
3495       INTERP_KERNEL::NormalizedCellType type;
3496       int dim_space=getSpaceDimension();
3497       const double *coords=getCoords()->getConstPointer();
3498       const int *connec=getNodalConnectivity()->getConstPointer();
3499       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3500       for(int iel=0;iel<nbelem;iel++)
3501         {
3502           ipt=connec_index[iel];
3503           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3504           area_vol[iel]=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[iel+1]-ipt-1,coords,dim_space);
3505         }
3506       if(isAbs)
3507         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3508     }
3509   else
3510     {
3511       area_vol[0]=std::numeric_limits<double>::max();
3512     }
3513   return field.retn();
3514 }
3515
3516 /*!
3517  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3518  * mesh.<br>
3519  * For 1D cells, the returned array contains lengths.<br>
3520  * For 2D cells, the returned array contains areas.<br>
3521  * For 3D cells, the returned array contains volumes.
3522  * This method avoids building explicitly a part of \a this mesh to perform the work.
3523  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3524  *         orientation, i.e. the volume is always positive.
3525  *  \param [in] begin - an array of cell ids of interest.
3526  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3527  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3528  *          delete this array using decrRef() as it is no more needed.
3529  * 
3530  *  \if ENABLE_EXAMPLES
3531  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3532  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3533  *  \endif
3534  *  \sa getMeasureField()
3535  */
3536 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3537 {
3538   std::string name="PartMeasureOfMesh_";
3539   name+=getName();
3540   int nbelem=(int)std::distance(begin,end);
3541   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3542   array->setName(name);
3543   array->alloc(nbelem,1);
3544   double *area_vol=array->getPointer();
3545   if(getMeshDimension()!=-1)
3546     {
3547       int ipt;
3548       INTERP_KERNEL::NormalizedCellType type;
3549       int dim_space=getSpaceDimension();
3550       const double *coords=getCoords()->getConstPointer();
3551       const int *connec=getNodalConnectivity()->getConstPointer();
3552       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3553       for(const int *iel=begin;iel!=end;iel++)
3554         {
3555           ipt=connec_index[*iel];
3556           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3557           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3558         }
3559       if(isAbs)
3560         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3561     }
3562   else
3563     {
3564       area_vol[0]=std::numeric_limits<double>::max();
3565     }
3566   return array.retn();
3567 }
3568
3569 /*!
3570  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3571  * \a this one. The returned field contains the dual cell volume for each corresponding
3572  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3573  *  the dual mesh in P1 sens of \a this.<br>
3574  * For 1D cells, the returned field contains lengths.<br>
3575  * For 2D cells, the returned field contains areas.<br>
3576  * For 3D cells, the returned field contains volumes.
3577  * This method is useful to check "P1*" conservative interpolators.
3578  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3579  *         orientation, i.e. the volume is always positive.
3580  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3581  *          nodes and one time. The caller is to delete this array using decrRef() as
3582  *          it is no more needed.
3583  */
3584 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3585 {
3586   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3587   std::string name="MeasureOnNodeOfMesh_";
3588   name+=getName();
3589   int nbNodes=getNumberOfNodes();
3590   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3591   double cst=1./((double)getMeshDimension()+1.);
3592   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3593   array->alloc(nbNodes,1);
3594   double *valsToFill=array->getPointer();
3595   std::fill(valsToFill,valsToFill+nbNodes,0.);
3596   const double *values=tmp->getArray()->getConstPointer();
3597   MCAuto<DataArrayInt> da=DataArrayInt::New();
3598   MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3599   getReverseNodalConnectivity(da,daInd);
3600   const int *daPtr=da->getConstPointer();
3601   const int *daIPtr=daInd->getConstPointer();
3602   for(int i=0;i<nbNodes;i++)
3603     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3604       valsToFill[i]+=cst*values[*cell];
3605   ret->setMesh(this);
3606   ret->setArray(array);
3607   return ret.retn();
3608 }
3609
3610 /*!
3611  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3612  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3613  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3614  * and are normalized.
3615  * <br> \a this can be either 
3616  * - a  2D mesh in 2D or 3D space or 
3617  * - an 1D mesh in 2D space.
3618  * 
3619  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3620  *          cells and one time. The caller is to delete this field using decrRef() as
3621  *          it is no more needed.
3622  *  \throw If the nodal connectivity of cells is not defined.
3623  *  \throw If the coordinates array is not set.
3624  *  \throw If the mesh dimension is not set.
3625  *  \throw If the mesh and space dimension is not as specified above.
3626  */
3627 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3628 {
3629   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3630     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3631   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3632   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3633   int nbOfCells=getNumberOfCells();
3634   int nbComp=getMeshDimension()+1;
3635   array->alloc(nbOfCells,nbComp);
3636   double *vals=array->getPointer();
3637   const int *connI=_nodal_connec_index->getConstPointer();
3638   const int *conn=_nodal_connec->getConstPointer();
3639   const double *coords=_coords->getConstPointer();
3640   if(getMeshDimension()==2)
3641     {
3642       if(getSpaceDimension()==3)
3643         {
3644           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3645           const double *locPtr=loc->getConstPointer();
3646           for(int i=0;i<nbOfCells;i++,vals+=3)
3647             {
3648               int offset=connI[i];
3649               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3650               double n=INTERP_KERNEL::norm<3>(vals);
3651               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3652             }
3653         }
3654       else
3655         {
3656           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3657           const double *isAbsPtr=isAbs->getArray()->begin();
3658           for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3659             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3660         }
3661     }
3662   else//meshdimension==1
3663     {
3664       double tmp[2];
3665       for(int i=0;i<nbOfCells;i++)
3666         {
3667           int offset=connI[i];
3668           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3669           double n=INTERP_KERNEL::norm<2>(tmp);
3670           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3671           *vals++=-tmp[1];
3672           *vals++=tmp[0];
3673         }
3674     }
3675   ret->setArray(array);
3676   ret->setMesh(this);
3677   ret->synchronizeTimeWithSupport();
3678   return ret.retn();
3679 }
3680
3681 /*!
3682  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3683  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3684  * and are normalized.
3685  * <br> \a this can be either 
3686  * - a  2D mesh in 2D or 3D space or 
3687  * - an 1D mesh in 2D space.
3688  * 
3689  * This method avoids building explicitly a part of \a this mesh to perform the work.
3690  *  \param [in] begin - an array of cell ids of interest.
3691  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3692  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3693  *          cells and one time. The caller is to delete this field using decrRef() as
3694  *          it is no more needed.
3695  *  \throw If the nodal connectivity of cells is not defined.
3696  *  \throw If the coordinates array is not set.
3697  *  \throw If the mesh dimension is not set.
3698  *  \throw If the mesh and space dimension is not as specified above.
3699  *  \sa buildOrthogonalField()
3700  *
3701  *  \if ENABLE_EXAMPLES
3702  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3703  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3704  *  \endif
3705  */
3706 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3707 {
3708   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3709     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3710   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3711   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3712   std::size_t nbelems=std::distance(begin,end);
3713   int nbComp=getMeshDimension()+1;
3714   array->alloc((int)nbelems,nbComp);
3715   double *vals=array->getPointer();
3716   const int *connI=_nodal_connec_index->getConstPointer();
3717   const int *conn=_nodal_connec->getConstPointer();
3718   const double *coords=_coords->getConstPointer();
3719   if(getMeshDimension()==2)
3720     {
3721       if(getSpaceDimension()==3)
3722         {
3723           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3724           const double *locPtr=loc->getConstPointer();
3725           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3726             {
3727               int offset=connI[*i];
3728               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3729               double n=INTERP_KERNEL::norm<3>(vals);
3730               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3731             }
3732         }
3733       else
3734         {
3735           for(std::size_t i=0;i<nbelems;i++)
3736             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3737         }
3738     }
3739   else//meshdimension==1
3740     {
3741       double tmp[2];
3742       for(const int *i=begin;i!=end;i++)
3743         {
3744           int offset=connI[*i];
3745           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3746           double n=INTERP_KERNEL::norm<2>(tmp);
3747           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3748           *vals++=-tmp[1];
3749           *vals++=tmp[0];
3750         }
3751     }
3752   ret->setArray(array);
3753   ret->setMesh(this);
3754   ret->synchronizeTimeWithSupport();
3755   return ret.retn();
3756 }
3757
3758 /*!
3759  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3760  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3761  * and are \b not normalized.
3762  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3763  *          cells and one time. The caller is to delete this field using decrRef() as
3764  *          it is no more needed.
3765  *  \throw If the nodal connectivity of cells is not defined.
3766  *  \throw If the coordinates array is not set.
3767  *  \throw If \a this->getMeshDimension() != 1.
3768  *  \throw If \a this mesh includes cells of type other than SEG2.
3769  */
3770 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3771 {
3772   if(getMeshDimension()!=1)
3773     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3774   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3775     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3776   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3777   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3778   int nbOfCells=getNumberOfCells();
3779   int spaceDim=getSpaceDimension();
3780   array->alloc(nbOfCells,spaceDim);
3781   double *pt=array->getPointer();
3782   const double *coo=getCoords()->getConstPointer();
3783   std::vector<int> conn;
3784   conn.reserve(2);
3785   for(int i=0;i<nbOfCells;i++)
3786     {
3787       conn.resize(0);
3788       getNodeIdsOfCell(i,conn);
3789       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3790     }
3791   ret->setArray(array);
3792   ret->setMesh(this);
3793   ret->synchronizeTimeWithSupport();
3794   return ret.retn();
3795 }
3796
3797 /*!
3798  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3799  * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3800  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3801  * from. If a result face is shared by two 3D cells, then the face in included twice in
3802  * the result mesh.
3803  *  \param [in] origin - 3 components of a point defining location of the plane.
3804  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3805  *         must be greater than 1e-6.
3806  *  \param [in] eps - half-thickness of the plane.
3807  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3808  *         producing correspondent 2D cells. The caller is to delete this array
3809  *         using decrRef() as it is no more needed.
3810  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3811  *         not share the node coordinates array with \a this mesh. The caller is to
3812  *         delete this mesh using decrRef() as it is no more needed.  
3813  *  \throw If the coordinates array is not set.
3814  *  \throw If the nodal connectivity of cells is not defined.
3815  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3816  *  \throw If magnitude of \a vec is less than 1e-6.
3817  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3818  *  \throw If \a this includes quadratic cells.
3819  */
3820 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3821 {
3822   checkFullyDefined();
3823   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3824     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3825   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3826   if(candidates->empty())
3827     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3828   std::vector<int> nodes;
3829   DataArrayInt *cellIds1D=0;
3830   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3831   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3832   MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3833   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3834   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3835   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3836   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3837   revDesc2=0; revDescIndx2=0;
3838   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3839   revDesc1=0; revDescIndx1=0;
3840   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3841   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3842   //
3843   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3844   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3845     cut3DCurve[*it]=-1;
3846   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3847   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3848   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3849                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3850                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3851   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3852   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3853   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3854   if(cellIds2->empty())
3855     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3856   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3857   ret->setCoords(mDesc1->getCoords());
3858   ret->setConnectivity(conn,connI,true);
3859   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3860   return ret.retn();
3861 }
3862
3863 /*!
3864  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3865 addition to the mesh, returns a new DataArrayInt, 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
3866 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3867 the result mesh.
3868  *  \param [in] origin - 3 components of a point defining location of the plane.
3869  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3870  *         must be greater than 1e-6.
3871  *  \param [in] eps - half-thickness of the plane.
3872  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3873  *         producing correspondent segments. The caller is to delete this array
3874  *         using decrRef() as it is no more needed.
3875  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3876  *         mesh in 3D space. This mesh does not share the node coordinates array with
3877  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3878  *         no more needed. 
3879  *  \throw If the coordinates array is not set.
3880  *  \throw If the nodal connectivity of cells is not defined.
3881  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3882  *  \throw If magnitude of \a vec is less than 1e-6.
3883  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3884  *  \throw If \a this includes quadratic cells.
3885  */
3886 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3887 {
3888   checkFullyDefined();
3889   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3890     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3891   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3892   if(candidates->empty())
3893     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3894   std::vector<int> nodes;
3895   DataArrayInt *cellIds1D=0;
3896   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3897   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3898   MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3899   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3900   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3901   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3902   MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3903   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3904   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3905   //
3906   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3907   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3908     cut3DCurve[*it]=-1;
3909   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3910   int ncellsSub=subMesh->getNumberOfCells();
3911   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3912   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3913                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3914                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3915   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3916   conn->alloc(0,1);
3917   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3918   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3919   for(int i=0;i<ncellsSub;i++)
3920     {
3921       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3922         {
3923           if(cut3DSurf[i].first!=-2)
3924             {
3925               conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3926               connI->pushBackSilent(conn->getNumberOfTuples());
3927               cellIds2->pushBackSilent(i);
3928             }
3929           else
3930             {
3931               int cellId3DSurf=cut3DSurf[i].second;
3932               int offset=nodalI[cellId3DSurf]+1;
3933               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3934               for(int j=0;j<nbOfEdges;j++)
3935                 {
3936                   conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3937                   connI->pushBackSilent(conn->getNumberOfTuples());
3938                   cellIds2->pushBackSilent(cellId3DSurf);
3939                 }
3940             }
3941         }
3942     }
3943   if(cellIds2->empty())
3944     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3945   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3946   ret->setCoords(mDesc1->getCoords());
3947   ret->setConnectivity(conn,connI,true);
3948   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3949   return ret.retn();
3950 }
3951
3952 /*!
3953  * Finds cells whose bounding boxes intersect a given plane.
3954  *  \param [in] origin - 3 components of a point defining location of the plane.
3955  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3956  *         must be greater than 1e-6.
3957  *  \param [in] eps - half-thickness of the plane.
3958  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3959  *         cells. The caller is to delete this array using decrRef() as it is no more
3960  *         needed.
3961  *  \throw If the coordinates array is not set.
3962  *  \throw If the nodal connectivity of cells is not defined.
3963  *  \throw If \a this->getSpaceDimension() != 3.
3964  *  \throw If magnitude of \a vec is less than 1e-6.
3965  *  \sa buildSlice3D()
3966  */
3967 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3968 {
3969   checkFullyDefined();
3970   if(getSpaceDimension()!=3)
3971     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3972   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3973   if(normm<1e-6)
3974     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3975   double vec2[3];
3976   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3977   double angle=acos(vec[2]/normm);
3978   MCAuto<DataArrayInt> cellIds;
3979   double bbox[6];
3980   if(angle>eps)
3981     {
3982       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3983       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3984       if(normm2/normm>1e-6)
3985         MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3986       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3987       mw->setCoords(coo);
3988       mw->getBoundingBox(bbox);
3989       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3990       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3991     }
3992   else
3993     {
3994       getBoundingBox(bbox);
3995       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3996       cellIds=getCellsInBoundingBox(bbox,eps);
3997     }
3998   return cellIds.retn();
3999 }
4000
4001 /*!
4002  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4003  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4004  * No consideration of coordinate is done by this method.
4005  * 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)
4006  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4007  */
4008 bool MEDCouplingUMesh::isContiguous1D() const
4009 {
4010   if(getMeshDimension()!=1)
4011     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4012   int nbCells=getNumberOfCells();
4013   if(nbCells<1)
4014     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4015   const int *connI=_nodal_connec_index->getConstPointer();
4016   const int *conn=_nodal_connec->getConstPointer();
4017   int ref=conn[connI[0]+2];
4018   for(int i=1;i<nbCells;i++)
4019     {
4020       if(conn[connI[i]+1]!=ref)
4021         return false;
4022       ref=conn[connI[i]+2];
4023     }
4024   return true;
4025 }
4026
4027 /*!
4028  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4029  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4030  * \param pt reference point of the line
4031  * \param v normalized director vector of the line
4032  * \param eps max precision before throwing an exception
4033  * \param res output of size this->getNumberOfCells
4034  */
4035 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4036 {
4037   if(getMeshDimension()!=1)
4038     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4039   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4040     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4041   if(getSpaceDimension()!=3)
4042     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4043   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4044   const double *fPtr=f->getArray()->getConstPointer();
4045   double tmp[3];
4046   for(int i=0;i<getNumberOfCells();i++)
4047     {
4048       const double *tmp1=fPtr+3*i;
4049       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4050       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4051       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4052       double n1=INTERP_KERNEL::norm<3>(tmp);
4053       n1/=INTERP_KERNEL::norm<3>(tmp1);
4054       if(n1>eps)
4055         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4056     }
4057   const double *coo=getCoords()->getConstPointer();
4058   for(int i=0;i<getNumberOfNodes();i++)
4059     {
4060       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4061       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4062       res[i]=std::accumulate(tmp,tmp+3,0.);
4063     }
4064 }
4065
4066 /*!
4067  * 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. 
4068  * \a this is expected to be a mesh so that its space dimension is equal to its
4069  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4070  * 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).
4071  *
4072  * 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
4073  * 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).
4074  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4075  *
4076  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4077  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4078  *
4079  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4080  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4081  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4082  * \return the positive value of the distance.
4083  * \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
4084  * dimension - 1.
4085  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4086  */
4087 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4088 {
4089   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4090   if(meshDim!=spaceDim-1)
4091     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4092   if(meshDim!=2 && meshDim!=1)
4093     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4094   checkFullyDefined();
4095   if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4096     { 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().c_str()); }
4097   DataArrayInt *ret1=0;
4098   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4099   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4100   MCAuto<DataArrayInt> ret1Safe(ret1);
4101   cellId=*ret1Safe->begin();
4102   return *ret0->begin();
4103 }
4104
4105 /*!
4106  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4107  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance. 
4108  * 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
4109  * 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).
4110  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4111  * 
4112  * \a this is expected to be a mesh so that its space dimension is equal to its
4113  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4114  * 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).
4115  *
4116  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4117  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4118  *
4119  * \param [in] pts the list of points in which each tuple represents a point
4120  * \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.
4121  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4122  * \throw if number of components of \a pts is not equal to the space dimension.
4123  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4124  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4125  */
4126 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4127 {
4128   if(!pts)
4129     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4130   pts->checkAllocated();
4131   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4132   if(meshDim!=spaceDim-1)
4133     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4134   if(meshDim!=2 && meshDim!=1)
4135     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4136   if(pts->getNumberOfComponents()!=spaceDim)
4137     {
4138       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4139       throw INTERP_KERNEL::Exception(oss.str().c_str());
4140     }
4141   checkFullyDefined();
4142   int nbCells=getNumberOfCells();
4143   if(nbCells==0)
4144     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4145   int nbOfPts=pts->getNumberOfTuples();
4146   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4147   MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4148   const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4149   double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4150   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4151   const double *bbox(bboxArr->begin());
4152   switch(spaceDim)
4153   {
4154     case 3:
4155       {
4156         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4157         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4158           {
4159             double x=std::numeric_limits<double>::max();
4160             std::vector<int> elems;
4161             myTree.getMinDistanceOfMax(ptsPtr,x);
4162             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4163             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4164           }
4165         break;
4166       }
4167     case 2:
4168       {
4169         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4170         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4171           {
4172             double x=std::numeric_limits<double>::max();
4173             std::vector<int> elems;
4174             myTree.getMinDistanceOfMax(ptsPtr,x);
4175             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4176             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4177           }
4178         break;
4179       }
4180     default:
4181       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4182   }
4183   cellIds=ret1.retn();
4184   return ret0.retn();
4185 }
4186
4187 /// @cond INTERNAL
4188
4189 /*!
4190  * \param [in] pt the start pointer (included) of the coordinates of the point
4191  * \param [in] cellIdsBg the start pointer (included) of cellIds
4192  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4193  * \param [in] nc nodal connectivity
4194  * \param [in] ncI nodal connectivity index
4195  * \param [in,out] ret0 the min distance between \a this and the external input point
4196  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4197  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4198  */
4199 void MEDCouplingUMesh::DistanceToPoint3DSurfAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId)
4200 {
4201   cellId=-1;
4202   ret0=std::numeric_limits<double>::max();
4203   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4204     {
4205       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4206       {
4207         case INTERP_KERNEL::NORM_TRI3:
4208           {
4209             double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4210             if(tmp<ret0)
4211               { ret0=tmp; cellId=*zeCell; }
4212             break;
4213           }
4214         case INTERP_KERNEL::NORM_QUAD4:
4215         case INTERP_KERNEL::NORM_POLYGON:
4216           {
4217             double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4218             if(tmp<ret0)
4219               { ret0=tmp; cellId=*zeCell; }
4220             break;
4221           }
4222         default:
4223           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4224       }
4225     }
4226 }
4227
4228 /*!
4229  * \param [in] pt the start pointer (included) of the coordinates of the point
4230  * \param [in] cellIdsBg the start pointer (included) of cellIds
4231  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4232  * \param [in] nc nodal connectivity
4233  * \param [in] ncI nodal connectivity index
4234  * \param [in,out] ret0 the min distance between \a this and the external input point
4235  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4236  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4237  */
4238 void MEDCouplingUMesh::DistanceToPoint2DCurveAlg(const double *pt, const int *cellIdsBg, const int *cellIdsEnd, const double *coords, const int *nc, const int *ncI, double& ret0, int& cellId)
4239 {
4240   cellId=-1;
4241   ret0=std::numeric_limits<double>::max();
4242   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4243     {
4244       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4245       {
4246         case INTERP_KERNEL::NORM_SEG2:
4247           {
4248             std::size_t uselessEntry=0;
4249             double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4250             tmp=sqrt(tmp);
4251             if(tmp<ret0)
4252               { ret0=tmp; cellId=*zeCell; }
4253             break;
4254           }
4255         default:
4256           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4257       }
4258     }
4259 }
4260 /// @endcond
4261
4262 /*!
4263  * Finds cells in contact with a ball (i.e. a point with precision). 
4264  * 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.
4265  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4266  *
4267  * \warning This method is suitable if the caller intends to evaluate only one
4268  *          point, for more points getCellsContainingPoints() is recommended as it is
4269  *          faster. 
4270  *  \param [in] pos - array of coordinates of the ball central point.
4271  *  \param [in] eps - ball radius.
4272  *  \return int - a smallest id of cells being in contact with the ball, -1 in case
4273  *         if there are no such cells.
4274  *  \throw If the coordinates array is not set.
4275  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4276  */
4277 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4278 {
4279   std::vector<int> elts;
4280   getCellsContainingPoint(pos,eps,elts);
4281   if(elts.empty())
4282     return -1;
4283   return elts.front();
4284 }
4285
4286 /*!
4287  * Finds cells in contact with a ball (i.e. a point with precision).
4288  * 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.
4289  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4290  * \warning This method is suitable if the caller intends to evaluate only one
4291  *          point, for more points getCellsContainingPoints() is recommended as it is
4292  *          faster. 
4293  *  \param [in] pos - array of coordinates of the ball central point.
4294  *  \param [in] eps - ball radius.
4295  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4296  *         before inserting ids.
4297  *  \throw If the coordinates array is not set.
4298  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4299  *
4300  *  \if ENABLE_EXAMPLES
4301  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4302  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4303  *  \endif
4304  */
4305 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4306 {
4307   MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4308   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4309   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4310 }
4311
4312 /// @cond INTERNAL
4313
4314 namespace MEDCoupling
4315 {
4316   template<const int SPACEDIMM>
4317   class DummyClsMCUG
4318   {
4319   public:
4320     static const int MY_SPACEDIM=SPACEDIMM;
4321     static const int MY_MESHDIM=8;
4322     typedef int MyConnType;
4323     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4324     // begin
4325     // useless, but for windows compilation ...
4326     const double* getCoordinatesPtr() const { return 0; }
4327     const int* getConnectivityPtr() const { return 0; }
4328     const int* getConnectivityIndexPtr() const { return 0; }
4329     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4330     // end
4331   };
4332
4333   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4334   {
4335     INTERP_KERNEL::Edge *ret(0);
4336     MCAuto<INTERP_KERNEL::Node> n0(new INTERP_KERNEL::Node(coords2D[2*bg[0]],coords2D[2*bg[0]+1])),n1(new INTERP_KERNEL::Node(coords2D[2*bg[1]],coords2D[2*bg[1]+1]));
4337     m[n0]=bg[0]; m[n1]=bg[1];
4338     switch(typ)
4339     {
4340       case INTERP_KERNEL::NORM_SEG2:
4341         {
4342           ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4343           break;
4344         }
4345       case INTERP_KERNEL::NORM_SEG3:
4346         {
4347           INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4348           INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4349           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4350           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4351           bool colinearity(inters.areColinears());
4352           delete e1; delete e2;
4353           if(colinearity)
4354             { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4355           else
4356             { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4357           break;
4358         }
4359       default:
4360         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4361     }
4362     return ret;
4363   }
4364
4365   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4366   {
4367     INTERP_KERNEL::Edge *ret=0;
4368     switch(typ)
4369     {
4370       case INTERP_KERNEL::NORM_SEG2:
4371         {
4372           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4373           break;
4374         }
4375       case INTERP_KERNEL::NORM_SEG3:
4376         {
4377           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4378           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4379           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4380           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4381           bool colinearity=inters.areColinears();
4382           delete e1; delete e2;
4383           if(colinearity)
4384             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4385           else
4386             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4387           mapp2[bg[2]].second=false;
4388           break;
4389         }
4390       default:
4391         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4392     }
4393     return ret;
4394   }
4395
4396   /*!
4397    * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4398    * the global mesh 'mDesc'.
4399    * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4400    * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4401    */
4402   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4403                                                                    std::map<INTERP_KERNEL::Node *,int>& mapp)
4404   {
4405     mapp.clear();
4406     std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;//bool is for a flag specifying if node is boundary (true) or only a middle for SEG3.
4407     const double *coo=mDesc->getCoords()->getConstPointer();
4408     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4409     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4410     std::set<int> s;
4411     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4412       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4413     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4414       {
4415         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4416         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4417       }
4418     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4419     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4420       {
4421         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4422         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4423       }
4424     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4425       {
4426         if((*it2).second.second)
4427           mapp[(*it2).second.first]=(*it2).first;
4428         ((*it2).second.first)->decrRef();
4429       }
4430     return ret;
4431   }
4432
4433   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4434   {
4435     if(nodeId>=offset2)
4436       {
4437         int locId=nodeId-offset2;
4438         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4439       }
4440     if(nodeId>=offset1)
4441       {
4442         int locId=nodeId-offset1;
4443         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4444       }
4445     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4446   }
4447
4448   /**
4449    * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4450    */
4451   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4452                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4453                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4454   {
4455     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4456       {
4457         int eltId1=abs(*desc1)-1;
4458         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4459           {
4460             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4461             if(it==mappRev.end())
4462               {
4463                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4464                 mapp[node]=*it1;
4465                 mappRev[*it1]=node;
4466               }
4467           }
4468       }
4469   }
4470 }
4471
4472 /// @endcond
4473
4474 template<int SPACEDIM>
4475 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4476                                                    double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4477 {
4478   elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4479   int *eltsIndexPtr(eltsIndex->getPointer());
4480   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4481   const double *bbox(bboxArr->begin());
4482   int nbOfCells=getNumberOfCells();
4483   const int *conn=_nodal_connec->getConstPointer();
4484   const int *connI=_nodal_connec_index->getConstPointer();
4485   double bb[2*SPACEDIM];
4486   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4487   for(int i=0;i<nbOfPoints;i++)
4488     {
4489       eltsIndexPtr[i+1]=eltsIndexPtr[i];
4490       for(int j=0;j<SPACEDIM;j++)
4491         {
4492           bb[2*j]=pos[SPACEDIM*i+j];
4493           bb[2*j+1]=pos[SPACEDIM*i+j];
4494         }
4495       std::vector<int> candidates;
4496       myTree.getIntersectingElems(bb,candidates);
4497       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4498         {
4499           int sz(connI[(*iter)+1]-connI[*iter]-1);
4500           INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4501           bool status(false);
4502           if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4503             status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4504           else
4505             {
4506               if(SPACEDIM!=2)
4507                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4508               INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4509               INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4510               std::vector<INTERP_KERNEL::Node *> nodes(sz);
4511               INTERP_KERNEL::QuadraticPolygon *pol(0);
4512               for(int j=0;j<sz;j++)
4513                 {
4514                   int nodeId(conn[connI[*iter]+1+j]);
4515                   nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4516                 }
4517               if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4518                 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4519               else
4520                 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4521               INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4522               double a(0.),b(0.),c(0.);
4523               a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4524               status=pol->isInOrOut2(n);
4525               delete pol; n->decrRef();
4526             }
4527           if(status)
4528             {
4529               eltsIndexPtr[i+1]++;
4530               elts->pushBackSilent(*iter);
4531             }
4532         }
4533     }
4534 }
4535 /*!
4536  * Finds cells in contact with several balls (i.e. points with precision).
4537  * This method is an extension of getCellContainingPoint() and
4538  * getCellsContainingPoint() for the case of multiple points.
4539  * 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.
4540  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4541  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4542  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4543  *         this->getSpaceDimension() * \a nbOfPoints 
4544  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4545  *  \param [in] eps - radius of balls (i.e. the precision).
4546  *  \param [out] elts - vector returning ids of found cells.
4547  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4548  *         dividing cell ids in \a elts into groups each referring to one
4549  *         point. Its every element (except the last one) is an index pointing to the
4550  *         first id of a group of cells. For example cells in contact with the *i*-th
4551  *         point are described by following range of indices:
4552  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4553  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4554  *         Number of cells in contact with the *i*-th point is
4555  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4556  *  \throw If the coordinates array is not set.
4557  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4558  *
4559  *  \if ENABLE_EXAMPLES
4560  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4561  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4562  *  \endif
4563  */
4564 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4565                                                 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4566 {
4567   int spaceDim=getSpaceDimension();
4568   int mDim=getMeshDimension();
4569   if(spaceDim==3)
4570     {
4571       if(mDim==3)
4572         {
4573           const double *coords=_coords->getConstPointer();
4574           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4575         }
4576       /*else if(mDim==2)
4577         {
4578
4579         }*/
4580       else
4581         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4582     }
4583   else if(spaceDim==2)
4584     {
4585       if(mDim==2)
4586         {
4587           const double *coords=_coords->getConstPointer();
4588           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4589         }
4590       else
4591         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4592     }
4593   else if(spaceDim==1)
4594     {
4595       if(mDim==1)
4596         {
4597           const double *coords=_coords->getConstPointer();
4598           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4599         }
4600       else
4601         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4602     }
4603   else
4604     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4605 }
4606
4607 /*!
4608  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4609  * least two its edges intersect each other anywhere except their extremities. An
4610  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4611  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4612  *         cleared before filling in.
4613  *  \param [in] eps - precision.
4614  *  \throw If \a this->getMeshDimension() != 2.
4615  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4616  */
4617 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4618 {
4619   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4620   if(getMeshDimension()!=2)
4621     throw INTERP_KERNEL::Exception(msg);
4622   int spaceDim=getSpaceDimension();
4623   if(spaceDim!=2 && spaceDim!=3)
4624     throw INTERP_KERNEL::Exception(msg);
4625   const int *conn=_nodal_connec->getConstPointer();
4626   const int *connI=_nodal_connec_index->getConstPointer();
4627   int nbOfCells=getNumberOfCells();
4628   std::vector<double> cell2DinS2;
4629   for(int i=0;i<nbOfCells;i++)
4630     {
4631       int offset=connI[i];
4632       int nbOfNodesForCell=connI[i+1]-offset-1;
4633       if(nbOfNodesForCell<=3)
4634         continue;
4635       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4636       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4637       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4638         cells.push_back(i);
4639       cell2DinS2.clear();
4640     }
4641 }
4642
4643 /*!
4644  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4645  *
4646  * 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.
4647  * 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.
4648  * 
4649  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4650  * This convex envelop is computed using Jarvis march algorithm.
4651  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4652  * 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)
4653  * 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.
4654  *
4655  * \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.
4656  * \sa MEDCouplingUMesh::colinearize2D
4657  */
4658 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4659 {
4660   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4661     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4662   checkFullyDefined();
4663   const double *coords=getCoords()->getConstPointer();
4664   int nbOfCells=getNumberOfCells();
4665   MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4666   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4667   MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4668   int *workIndexOut=nodalConnecIndexOut->getPointer();
4669   *workIndexOut=0;
4670   const int *nodalConnecIn=_nodal_connec->getConstPointer();
4671   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4672   std::set<INTERP_KERNEL::NormalizedCellType> types;
4673   MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4674   isChanged->alloc(0,1);
4675   for(int i=0;i<nbOfCells;i++,workIndexOut++)
4676     {
4677       int pos=nodalConnecOut->getNumberOfTuples();
4678       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4679         isChanged->pushBackSilent(i);
4680       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4681       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4682     }
4683   if(isChanged->empty())
4684     return 0;
4685   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4686   _types=types;
4687   return isChanged.retn();
4688 }
4689
4690 /*!
4691  * This method is \b NOT const because it can modify \a this.
4692  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4693  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4694  * \param policy specifies the type of extrusion chosen:
4695  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4696  *   will be repeated to build each level
4697  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4698  *   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
4699  *   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
4700  *   arc.
4701  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.  
4702  */
4703 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4704 {
4705   checkFullyDefined();
4706   mesh1D->checkFullyDefined();
4707   if(!mesh1D->isContiguous1D())
4708     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4709   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4710     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4711   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4712     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4713   if(mesh1D->getMeshDimension()!=1)
4714     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4715   bool isQuad=false;
4716   if(isPresenceOfQuadratic())
4717     {
4718       if(mesh1D->isFullyQuadratic())
4719         isQuad=true;
4720       else
4721         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4722     }
4723   int oldNbOfNodes(getNumberOfNodes());
4724   MCAuto<DataArrayDouble> newCoords;
4725   switch(policy)
4726   {
4727     case 0:
4728       {
4729         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4730         break;
4731       }
4732     case 1:
4733       {
4734         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4735         break;
4736       }
4737     default:
4738       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4739   }
4740   setCoords(newCoords);
4741   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4742   updateTime();
4743   return ret.retn();
4744 }
4745
4746 /*!
4747  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4748  * If it is not the case an exception will be thrown.
4749  * This method is non const because the coordinate of \a this can be appended with some new points issued from
4750  * intersection of plane defined by ('origin','vec').
4751  * This method has one in/out parameter : 'cut3DCurve'.
4752  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4753  * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4754  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4755  * This method will throw an exception if \a this contains a non linear segment.
4756  */
4757 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4758 {
4759   checkFullyDefined();
4760   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4761     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4762   int ncells=getNumberOfCells();
4763   int nnodes=getNumberOfNodes();
4764   double vec2[3],vec3[3],vec4[3];
4765   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4766   if(normm<1e-6)
4767     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4768   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4769   const int *conn=_nodal_connec->getConstPointer();
4770   const int *connI=_nodal_connec_index->getConstPointer();
4771   const double *coo=_coords->getConstPointer();
4772   std::vector<double> addCoo;
4773   for(int i=0;i<ncells;i++)
4774     {
4775       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4776         {
4777           if(cut3DCurve[i]==-2)
4778             {
4779               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4780               vec3[0]=coo[3*endd]-coo[3*st]; vec3[1]=coo[3*endd+1]-coo[3*st+1]; vec3[2]=coo[3*endd+2]-coo[3*st+2];
4781               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4782               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4783               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4784                 {
4785                   const double *st2=coo+3*st;
4786                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4787                   double pos=-(vec4[0]*vec2[0]+vec4[1]*vec2[1]+vec4[2]*vec2[2])/((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2]));
4788                   if(pos>eps && pos<1-eps)
4789                     {
4790                       int nNode=((int)addCoo.size())/3;
4791                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4792                       addCoo.insert(addCoo.end(),vec4,vec4+3);
4793                       cut3DCurve[i]=nnodes+nNode;
4794                     }
4795                 }
4796             }
4797         }
4798       else
4799         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4800     }
4801   if(!addCoo.empty())
4802     {
4803       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4804       MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4805       coo2->alloc(newNbOfNodes,3);
4806       double *tmp=coo2->getPointer();
4807       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4808       std::copy(addCoo.begin(),addCoo.end(),tmp);
4809       DataArrayDouble::SetArrayIn(coo2,_coords);
4810     }
4811 }
4812
4813 /*!
4814  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4815  * \param mesh1D is the input 1D mesh used for translation computation.
4816  * \return newCoords new coords filled by this method. 
4817  */
4818 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4819 {
4820   int oldNbOfNodes=getNumberOfNodes();
4821   int nbOf1DCells=mesh1D->getNumberOfCells();
4822   int spaceDim=getSpaceDimension();
4823   DataArrayDouble *ret=DataArrayDouble::New();
4824   std::vector<bool> isQuads;
4825   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4826   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4827   double *retPtr=ret->getPointer();
4828   const double *coords=getCoords()->getConstPointer();
4829   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4830   std::vector<int> v;
4831   std::vector<double> c;
4832   double vec[3];
4833   v.reserve(3);
4834   c.reserve(6);
4835   for(int i=0;i<nbOf1DCells;i++)
4836     {
4837       v.resize(0);
4838       mesh1D->getNodeIdsOfCell(i,v);
4839       c.resize(0);
4840       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4841       mesh1D->getCoordinatesOfNode(v[0],c);
4842       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4843       for(int j=0;j<oldNbOfNodes;j++)
4844         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4845       if(isQuad)
4846         {
4847           c.resize(0);
4848           mesh1D->getCoordinatesOfNode(v[1],c);
4849           mesh1D->getCoordinatesOfNode(v[0],c);
4850           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4851           for(int j=0;j<oldNbOfNodes;j++)
4852             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4853         }
4854     }
4855   ret->copyStringInfoFrom(*getCoords());
4856   return ret;
4857 }
4858
4859 /*!
4860  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4861  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4862  * \return newCoords new coords filled by this method. 
4863  */
4864 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4865 {
4866   if(mesh1D->getSpaceDimension()==2)
4867     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4868   if(mesh1D->getSpaceDimension()==3)
4869     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4870   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4871 }
4872
4873 /*!
4874  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4875  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4876  * \return newCoords new coords filled by this method. 
4877  */
4878 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4879 {
4880   if(isQuad)
4881     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4882   int oldNbOfNodes=getNumberOfNodes();
4883   int nbOf1DCells=mesh1D->getNumberOfCells();
4884   if(nbOf1DCells<2)
4885     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4886   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4887   int nbOfLevsInVec=nbOf1DCells+1;
4888   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4889   double *retPtr=ret->getPointer();
4890   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4891   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4892   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4893   tmp->setCoords(tmp2);
4894   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4895   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4896   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4897   for(int i=1;i<nbOfLevsInVec;i++)
4898     {
4899       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4900       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4901       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4902       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4903       tmp->translate(vec);
4904       double tmp3[2],radius,alpha,alpha0;
4905       const double *p0=i+1<nbOfLevsInVec?begin:third;
4906       const double *p1=i+1<nbOfLevsInVec?end:begin;
4907       const double *p2=i+1<nbOfLevsInVec?third:end;
4908       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4909       double cosangle=i+1<nbOfLevsInVec?(p0[0]-tmp3[0])*(p1[0]-tmp3[0])+(p0[1]-tmp3[1])*(p1[1]-tmp3[1]):(p2[0]-tmp3[0])*(p1[0]-tmp3[0])+(p2[1]-tmp3[1])*(p1[1]-tmp3[1]);
4910       double angle=acos(cosangle/(radius*radius));
4911       tmp->rotate(end,0,angle);
4912       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4913     }
4914   return ret.retn();
4915 }
4916
4917 /*!
4918  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4919  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4920  * \return newCoords new coords filled by this method. 
4921  */
4922 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4923 {
4924   if(isQuad)
4925     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4926   int oldNbOfNodes=getNumberOfNodes();
4927   int nbOf1DCells=mesh1D->getNumberOfCells();
4928   if(nbOf1DCells<2)
4929     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4930   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4931   int nbOfLevsInVec=nbOf1DCells+1;
4932   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4933   double *retPtr=ret->getPointer();
4934   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4935   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4936   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4937   tmp->setCoords(tmp2);
4938   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4939   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4940   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4941   for(int i=1;i<nbOfLevsInVec;i++)
4942     {
4943       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4944       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4945       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4946       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4947       tmp->translate(vec);
4948       double tmp3[2],radius,alpha,alpha0;
4949       const double *p0=i+1<nbOfLevsInVec?begin:third;
4950       const double *p1=i+1<nbOfLevsInVec?end:begin;
4951       const double *p2=i+1<nbOfLevsInVec?third:end;
4952       double vecPlane[3]={
4953         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4954         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4955         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4956       };
4957       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4958       if(norm>1.e-7)
4959         {
4960           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4961           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4962           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4963           double s2=norm2;
4964           double c2=cos(asin(s2));
4965           double m[3][3]={
4966             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4967             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4968             {-vec2[1]*s2, vec2[0]*s2, c2}
4969           };
4970           double p0r[3]={m[0][0]*p0[0]+m[0][1]*p0[1]+m[0][2]*p0[2], m[1][0]*p0[0]+m[1][1]*p0[1]+m[1][2]*p0[2], m[2][0]*p0[0]+m[2][1]*p0[1]+m[2][2]*p0[2]};
4971           double p1r[3]={m[0][0]*p1[0]+m[0][1]*p1[1]+m[0][2]*p1[2], m[1][0]*p1[0]+m[1][1]*p1[1]+m[1][2]*p1[2], m[2][0]*p1[0]+m[2][1]*p1[1]+m[2][2]*p1[2]};
4972           double p2r[3]={m[0][0]*p2[0]+m[0][1]*p2[1]+m[0][2]*p2[2], m[1][0]*p2[0]+m[1][1]*p2[1]+m[1][2]*p2[2], m[2][0]*p2[0]+m[2][1]*p2[1]+m[2][2]*p2[2]};
4973           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4974           double cosangle=i+1<nbOfLevsInVec?(p0r[0]-tmp3[0])*(p1r[0]-tmp3[0])+(p0r[1]-tmp3[1])*(p1r[1]-tmp3[1]):(p2r[0]-tmp3[0])*(p1r[0]-tmp3[0])+(p2r[1]-tmp3[1])*(p1r[1]-tmp3[1]);
4975           double angle=acos(cosangle/(radius*radius));
4976           tmp->rotate(end,vecPlane,angle);
4977         }
4978       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4979     }
4980   return ret.retn();
4981 }
4982
4983 /*!
4984  * This method is private because not easy to use for end user. This method is const contrary to
4985  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4986  * the coords sorted slice by slice.
4987  * \param isQuad specifies presence of quadratic cells.
4988  */
4989 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4990 {
4991   int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
4992   int nbOf2DCells(getNumberOfCells());
4993   int nbOf3DCells(nbOf2DCells*nbOf1DCells);
4994   MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
4995   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
4996   MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4997   newConnI->alloc(nbOf3DCells+1,1);
4998   int *newConnIPtr(newConnI->getPointer());
4999   *newConnIPtr++=0;
5000   std::vector<int> newc;
5001   for(int j=0;j<nbOf2DCells;j++)
5002     {
5003       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5004       *newConnIPtr++=(int)newc.size();
5005     }
5006   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5007   int *newConnPtr(newConn->getPointer());
5008   int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5009   newConnIPtr=newConnI->getPointer();
5010   for(int iz=0;iz<nbOf1DCells;iz++)
5011     {
5012       if(iz!=0)
5013         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5014       const int *posOfTypeOfCell(newConnIPtr);
5015       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5016         {
5017           int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5018           if(icell!=*posOfTypeOfCell)
5019             {
5020               if(*iter!=-1)
5021                 *newConnPtr=(*iter)+iz*deltaPerLev;
5022               else
5023                 *newConnPtr=-1;
5024             }
5025           else
5026             {
5027               *newConnPtr=*iter;
5028               posOfTypeOfCell++;
5029             }
5030         }
5031     }
5032   ret->setConnectivity(newConn,newConnI,true);
5033   ret->setCoords(getCoords());
5034   return ret;
5035 }
5036
5037 /*!
5038  * Checks if \a this mesh is constituted by only quadratic cells.
5039  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
5040  *  \throw If the coordinates array is not set.
5041  *  \throw If the nodal connectivity of cells is not defined.
5042  */
5043 bool MEDCouplingUMesh::isFullyQuadratic() const
5044 {
5045   checkFullyDefined();
5046   bool ret=true;
5047   int nbOfCells=getNumberOfCells();
5048   for(int i=0;i<nbOfCells && ret;i++)
5049     {
5050       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5051       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5052       ret=cm.isQuadratic();
5053     }
5054   return ret;
5055 }
5056
5057 /*!
5058  * Checks if \a this mesh includes any quadratic cell.
5059  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5060  *  \throw If the coordinates array is not set.
5061  *  \throw If the nodal connectivity of cells is not defined.
5062  */
5063 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5064 {
5065   checkFullyDefined();
5066   bool ret=false;
5067   int nbOfCells=getNumberOfCells();
5068   for(int i=0;i<nbOfCells && !ret;i++)
5069     {
5070       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5071       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5072       ret=cm.isQuadratic();
5073     }
5074   return ret;
5075 }
5076
5077 /*!
5078  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5079  * this mesh, it remains unchanged.
5080  *  \throw If the coordinates array is not set.
5081  *  \throw If the nodal connectivity of cells is not defined.
5082  */
5083 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5084 {
5085   checkFullyDefined();
5086   int nbOfCells=getNumberOfCells();
5087   int delta=0;
5088   const int *iciptr=_nodal_connec_index->getConstPointer();
5089   for(int i=0;i<nbOfCells;i++)
5090     {
5091       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5092       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5093       if(cm.isQuadratic())
5094         {
5095           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5096           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5097           if(!cml.isDynamic())
5098             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5099           else
5100             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5101         }
5102     }
5103   if(delta==0)
5104     return ;
5105   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5106   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5107   const int *icptr=_nodal_connec->getConstPointer();
5108   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5109   newConnI->alloc(nbOfCells+1,1);
5110   int *ocptr=newConn->getPointer();
5111   int *ociptr=newConnI->getPointer();
5112   *ociptr=0;
5113   _types.clear();
5114   for(int i=0;i<nbOfCells;i++,ociptr++)
5115     {
5116       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5117       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5118       if(!cm.isQuadratic())
5119         {
5120           _types.insert(type);
5121           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5122           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5123         }
5124       else
5125         {
5126           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5127           _types.insert(typel);
5128           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5129           int newNbOfNodes=cml.getNumberOfNodes();
5130           if(cml.isDynamic())
5131             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5132           *ocptr++=(int)typel;
5133           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5134           ociptr[1]=ociptr[0]+newNbOfNodes+1;
5135         }
5136     }
5137   setConnectivity(newConn,newConnI,false);
5138 }
5139
5140 /*!
5141  * This method converts all linear cell in \a this to quadratic one.
5142  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5143  * 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)
5144  * 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.
5145  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5146  * end of the existing coordinates.
5147  * 
5148  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5149  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
5150  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5151  * 
5152  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5153  *
5154  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5155  */
5156 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5157 {
5158   DataArrayInt *conn=0,*connI=0;
5159   DataArrayDouble *coords=0;
5160   std::set<INTERP_KERNEL::NormalizedCellType> types;
5161   checkFullyDefined();
5162   MCAuto<DataArrayInt> ret,connSafe,connISafe;
5163   MCAuto<DataArrayDouble> coordsSafe;
5164   int meshDim=getMeshDimension();
5165   switch(conversionType)
5166   {
5167     case 0:
5168       switch(meshDim)
5169       {
5170         case 1:
5171           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5172           connSafe=conn; connISafe=connI; coordsSafe=coords;
5173           break;
5174         case 2:
5175           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5176           connSafe=conn; connISafe=connI; coordsSafe=coords;
5177           break;
5178         case 3:
5179           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5180           connSafe=conn; connISafe=connI; coordsSafe=coords;
5181           break;
5182         default:
5183           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5184       }
5185       break;
5186         case 1:
5187           {
5188             switch(meshDim)
5189             {
5190               case 1:
5191                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5192                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5193                 break;
5194               case 2:
5195                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5196                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5197                 break;
5198               case 3:
5199                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5200                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5201                 break;
5202               default:
5203                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5204             }
5205             break;
5206           }
5207         default:
5208           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5209   }
5210   setConnectivity(connSafe,connISafe,false);
5211   _types=types;
5212   setCoords(coordsSafe);
5213   return ret.retn();
5214 }
5215
5216 /*!
5217  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5218  * so that the number of cells remains the same. Quadratic faces are converted to
5219  * polygons. This method works only for 2D meshes in
5220  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5221  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5222  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5223  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5224  *         a polylinized edge constituting the input polygon.
5225  *  \throw If the coordinates array is not set.
5226  *  \throw If the nodal connectivity of cells is not defined.
5227  *  \throw If \a this->getMeshDimension() != 2.
5228  *  \throw If \a this->getSpaceDimension() != 2.
5229  */
5230 void MEDCouplingUMesh::tessellate2D(double eps)
5231 {
5232   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5233   if(spaceDim!=2)
5234     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5235   switch(meshDim)
5236     {
5237     case 1:
5238       return tessellate2DCurveInternal(eps);
5239     case 2:
5240       return tessellate2DInternal(eps);
5241     default:
5242       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5243     }
5244 }
5245 /*!
5246  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5247  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5248  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5249  *         a sub-divided edge.
5250  *  \throw If the coordinates array is not set.
5251  *  \throw If the nodal connectivity of cells is not defined.
5252  *  \throw If \a this->getMeshDimension() != 1.
5253  *  \throw If \a this->getSpaceDimension() != 2.
5254  */
5255
5256 #if 0
5257 /*!
5258  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5259  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5260  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
5261  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5262  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5263  * This method can be seen as the opposite method of colinearize2D.
5264  * 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
5265  * to avoid to modify the numbering of existing nodes.
5266  *
5267  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5268  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5269  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5270  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5271  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5272  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5273  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5274  *
5275  * \sa buildDescendingConnectivity2
5276  */
5277 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5278                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5279 {
5280   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5281     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5282   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5283   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5284     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5285   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5286     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5287   //DataArrayInt *out0(0),*outi0(0);
5288   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5289   //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5290   //out0s=out0s->buildUnique(); out0s->sort(true);
5291 }
5292 #endif
5293
5294 /*!
5295  * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5296  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5297  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5298  */
5299 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5300 {
5301   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5302   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5303   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5304   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5305   int nbOfCells=getNumberOfCells();
5306   int nbOfNodes=getNumberOfNodes();
5307   const int *cPtr=_nodal_connec->getConstPointer();
5308   const int *icPtr=_nodal_connec_index->getConstPointer();
5309   int lastVal=0,offset=nbOfNodes;
5310   for(int i=0;i<nbOfCells;i++,icPtr++)
5311     {
5312       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5313       if(type==INTERP_KERNEL::NORM_SEG2)
5314         {
5315           types.insert(INTERP_KERNEL::NORM_SEG3);
5316           newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5317           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5318           newConn->pushBackSilent(offset++);
5319           lastVal+=4;
5320           newConnI->pushBackSilent(lastVal);
5321           ret->pushBackSilent(i);
5322         }
5323       else
5324         {
5325           types.insert(type);
5326           lastVal+=(icPtr[1]-icPtr[0]);
5327           newConnI->pushBackSilent(lastVal);
5328           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5329         }
5330     }
5331   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5332   coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5333   return ret.retn();
5334 }
5335
5336 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2DAnd3D0(const MEDCouplingUMesh *m1D, const DataArrayInt *desc, const DataArrayInt *descI, DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5337 {
5338   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5339   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5340   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5341   //
5342   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5343   DataArrayInt *conn1D=0,*conn1DI=0;
5344   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5345   DataArrayDouble *coordsTmp=0;
5346   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5347   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5348   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5349   const int *c1DPtr=conn1D->begin();
5350   const int *c1DIPtr=conn1DI->begin();
5351   int nbOfCells=getNumberOfCells();
5352   const int *cPtr=_nodal_connec->getConstPointer();
5353   const int *icPtr=_nodal_connec_index->getConstPointer();
5354   int lastVal=0;
5355   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5356     {
5357       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5358       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5359       if(!cm.isQuadratic())
5360         {
5361           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5362           types.insert(typ2); newConn->pushBackSilent(typ2);
5363           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5364           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5365             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5366           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5367           newConnI->pushBackSilent(lastVal);
5368           ret->pushBackSilent(i);
5369         }
5370       else
5371         {
5372           types.insert(typ);
5373           lastVal+=(icPtr[1]-icPtr[0]);
5374           newConnI->pushBackSilent(lastVal);
5375           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5376         }
5377     }
5378   conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5379   return ret.retn();
5380 }
5381
5382 /*!
5383  * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5384  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5385  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5386  */
5387 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5388 {
5389   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5390   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5391   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5392 }
5393
5394 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5395 {
5396   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5397   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5398   //
5399   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5400   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5401   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5402   //
5403   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5404   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5405   DataArrayInt *conn1D=0,*conn1DI=0;
5406   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5407   DataArrayDouble *coordsTmp=0;
5408   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5409   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5410   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5411   const int *c1DPtr=conn1D->begin();
5412   const int *c1DIPtr=conn1DI->begin();
5413   int nbOfCells=getNumberOfCells();
5414   const int *cPtr=_nodal_connec->getConstPointer();
5415   const int *icPtr=_nodal_connec_index->getConstPointer();
5416   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5417   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5418     {
5419       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5420       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5421       if(!cm.isQuadratic())
5422         {
5423           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5424           types.insert(typ2); newConn->pushBackSilent(typ2);
5425           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5426           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5427             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5428           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5429           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5430           newConnI->pushBackSilent(lastVal);
5431           ret->pushBackSilent(i);
5432         }
5433       else
5434         {
5435           types.insert(typ);
5436           lastVal+=(icPtr[1]-icPtr[0]);
5437           newConnI->pushBackSilent(lastVal);
5438           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5439         }
5440     }
5441   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5442   coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5443   return ret.retn();
5444 }
5445
5446 /*!
5447  * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5448  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5449  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5450  */
5451 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5452 {
5453   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5454   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5455   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5456 }
5457
5458 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5459 {
5460   MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5461   MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5462   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5463   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5464   //
5465   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5466   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5467   MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5468   //
5469   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5470   const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5471   DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5472   std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5473   DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5474   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5475   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5476   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5477   MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5478   MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5479   MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5480   const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5481   int nbOfCells=getNumberOfCells();
5482   const int *cPtr=_nodal_connec->getConstPointer();
5483   const int *icPtr=_nodal_connec_index->getConstPointer();
5484   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5485   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5486     {
5487       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5488       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5489       if(!cm.isQuadratic())
5490         {
5491           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5492           if(typ2==INTERP_KERNEL::NORM_ERROR)
5493             {
5494               std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5495               throw INTERP_KERNEL::Exception(oss.str().c_str());
5496             }
5497           types.insert(typ2); newConn->pushBackSilent(typ2);
5498           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5499           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5500             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5501           for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5502             {
5503               int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5504               int tmpPos=newConn->getNumberOfTuples();
5505               newConn->pushBackSilent(nodeId2);
5506               ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5507             }
5508           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5509           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5510           newConnI->pushBackSilent(lastVal);
5511           ret->pushBackSilent(i);
5512         }
5513       else
5514         {
5515           types.insert(typ);
5516           lastVal+=(icPtr[1]-icPtr[0]);
5517           newConnI->pushBackSilent(lastVal);
5518           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5519         }
5520     }
5521   MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5522   MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5523   coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5524   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5525   std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5526   int *c=newConn->getPointer();
5527   const int *cI(newConnI->begin());
5528   for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5529     c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5530   offset=coordsTmp2Safe->getNumberOfTuples();
5531   for(const int *elt=ret->begin();elt!=ret->end();elt++)
5532     c[cI[(*elt)+1]-1]+=offset;
5533   coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5534   return ret.retn();
5535 }
5536
5537 /*!
5538  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5539  * In addition, returns an array mapping new cells to old ones. <br>
5540  * This method typically increases the number of cells in \a this mesh
5541  * but the number of nodes remains \b unchanged.
5542  * That's why the 3D splitting policies
5543  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5544  *  \param [in] policy - specifies a pattern used for splitting.
5545  * The semantic of \a policy is:
5546  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5547  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5548  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5549  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5550  *
5551  *
5552  *  \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5553  *          an id of old cell producing it. The caller is to delete this array using
5554  *         decrRef() as it is no more needed.
5555  *
5556  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5557  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5558  *          and \a this->getMeshDimension() != 3. 
5559  *  \throw If \a policy is not one of the four discussed above.
5560  *  \throw If the nodal connectivity of cells is not defined.
5561  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5562  */
5563 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5564 {
5565   switch(policy)
5566   {
5567     case 0:
5568       return simplexizePol0();
5569     case 1:
5570       return simplexizePol1();
5571     case (int) INTERP_KERNEL::PLANAR_FACE_5:
5572         return simplexizePlanarFace5();
5573     case (int) INTERP_KERNEL::PLANAR_FACE_6:
5574         return simplexizePlanarFace6();
5575     default:
5576       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)");
5577   }
5578 }
5579
5580 /*!
5581  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5582  * - 1D: INTERP_KERNEL::NORM_SEG2
5583  * - 2D: INTERP_KERNEL::NORM_TRI3
5584  * - 3D: INTERP_KERNEL::NORM_TETRA4.
5585  *
5586  * This method is useful for users that need to use P1 field services as
5587  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5588  * All these methods need mesh support containing only simplex cells.
5589  *  \return bool - \c true if there are only simplex cells in \a this mesh.
5590  *  \throw If the coordinates array is not set.
5591  *  \throw If the nodal connectivity of cells is not defined.
5592  *  \throw If \a this->getMeshDimension() < 1.
5593  */
5594 bool MEDCouplingUMesh::areOnlySimplexCells() const
5595 {
5596   checkFullyDefined();
5597   int mdim=getMeshDimension();
5598   if(mdim<1 || mdim>3)
5599     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5600   int nbCells=getNumberOfCells();
5601   const int *conn=_nodal_connec->getConstPointer();
5602   const int *connI=_nodal_connec_index->getConstPointer();
5603   for(int i=0;i<nbCells;i++)
5604     {
5605       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5606       if(!cm.isSimplex())
5607         return false;
5608     }
5609   return true;
5610 }
5611
5612 /*!
5613  * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5614  */
5615 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5616 {
5617   checkConnectivityFullyDefined();
5618   if(getMeshDimension()!=2)
5619     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5620   int nbOfCells=getNumberOfCells();
5621   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5622   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5623   ret->alloc(nbOfCells+nbOfCutCells,1);
5624   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5625   int *retPt=ret->getPointer();
5626   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5627   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5628   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5629   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5630   int *pt=newConn->getPointer();
5631   int *ptI=newConnI->getPointer();
5632   ptI[0]=0;
5633   const int *oldc=_nodal_connec->getConstPointer();
5634   const int *ci=_nodal_connec_index->getConstPointer();
5635   for(int i=0;i<nbOfCells;i++,ci++)
5636     {
5637       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5638         {
5639           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5640             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5641           pt=std::copy(tmp,tmp+8,pt);
5642           ptI[1]=ptI[0]+4;
5643           ptI[2]=ptI[0]+8;
5644           *retPt++=i;
5645           *retPt++=i;
5646           ptI+=2;
5647         }
5648       else
5649         {
5650           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5651           ptI[1]=ptI[0]+ci[1]-ci[0];
5652           ptI++;
5653           *retPt++=i;
5654         }
5655     }
5656   _nodal_connec->decrRef();
5657   _nodal_connec=newConn.retn();
5658   _nodal_connec_index->decrRef();
5659   _nodal_connec_index=newConnI.retn();
5660   computeTypes();
5661   updateTime();
5662   return ret.retn();
5663 }
5664
5665 /*!
5666  * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5667  */
5668 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5669 {
5670   checkConnectivityFullyDefined();
5671   if(getMeshDimension()!=2)
5672     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5673   int nbOfCells=getNumberOfCells();
5674   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5675   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5676   ret->alloc(nbOfCells+nbOfCutCells,1);
5677   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5678   int *retPt=ret->getPointer();
5679   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5680   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5681   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5682   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5683   int *pt=newConn->getPointer();
5684   int *ptI=newConnI->getPointer();
5685   ptI[0]=0;
5686   const int *oldc=_nodal_connec->getConstPointer();
5687   const int *ci=_nodal_connec_index->getConstPointer();
5688   for(int i=0;i<nbOfCells;i++,ci++)
5689     {
5690       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5691         {
5692           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5693             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5694           pt=std::copy(tmp,tmp+8,pt);
5695           ptI[1]=ptI[0]+4;
5696           ptI[2]=ptI[0]+8;
5697           *retPt++=i;
5698           *retPt++=i;
5699           ptI+=2;
5700         }
5701       else
5702         {
5703           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5704           ptI[1]=ptI[0]+ci[1]-ci[0];
5705           ptI++;
5706           *retPt++=i;
5707         }
5708     }
5709   _nodal_connec->decrRef();
5710   _nodal_connec=newConn.retn();
5711   _nodal_connec_index->decrRef();
5712   _nodal_connec_index=newConnI.retn();
5713   computeTypes();
5714   updateTime();
5715   return ret.retn();
5716 }
5717
5718 /*!
5719  * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5720  */
5721 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5722 {
5723   checkConnectivityFullyDefined();
5724   if(getMeshDimension()!=3)
5725     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5726   int nbOfCells=getNumberOfCells();
5727   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5728   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5729   ret->alloc(nbOfCells+4*nbOfCutCells,1);
5730   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5731   int *retPt=ret->getPointer();
5732   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5733   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5734   newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5735   newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5736   int *pt=newConn->getPointer();
5737   int *ptI=newConnI->getPointer();
5738   ptI[0]=0;
5739   const int *oldc=_nodal_connec->getConstPointer();
5740   const int *ci=_nodal_connec_index->getConstPointer();
5741   for(int i=0;i<nbOfCells;i++,ci++)
5742     {
5743       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5744         {
5745           for(int j=0;j<5;j++,pt+=5,ptI++)
5746             {
5747               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5748               pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_5_WO[4*j+3]+1];
5749               *retPt++=i;
5750               ptI[1]=ptI[0]+5;
5751             }
5752         }
5753       else
5754         {
5755           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5756           ptI[1]=ptI[0]+ci[1]-ci[0];
5757           ptI++;
5758           *retPt++=i;
5759         }
5760     }
5761   _nodal_connec->decrRef();
5762   _nodal_connec=newConn.retn();
5763   _nodal_connec_index->decrRef();
5764   _nodal_connec_index=newConnI.retn();
5765   computeTypes();
5766   updateTime();
5767   return ret.retn();
5768 }
5769
5770 /*!
5771  * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5772  */
5773 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5774 {
5775   checkConnectivityFullyDefined();
5776   if(getMeshDimension()!=3)
5777     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5778   int nbOfCells=getNumberOfCells();
5779   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5780   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5781   ret->alloc(nbOfCells+5*nbOfCutCells,1);
5782   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5783   int *retPt=ret->getPointer();
5784   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5785   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5786   newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5787   newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5788   int *pt=newConn->getPointer();
5789   int *ptI=newConnI->getPointer();
5790   ptI[0]=0;
5791   const int *oldc=_nodal_connec->getConstPointer();
5792   const int *ci=_nodal_connec_index->getConstPointer();
5793   for(int i=0;i<nbOfCells;i++,ci++)
5794     {
5795       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5796         {
5797           for(int j=0;j<6;j++,pt+=5,ptI++)
5798             {
5799               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5800               pt[1]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+0]+1]; pt[2]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+1]+1]; pt[3]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+2]+1]; pt[4]=oldc[ci[0]+INTERP_KERNEL::SPLIT_NODES_6_WO[4*j+3]+1];
5801               *retPt++=i;
5802               ptI[1]=ptI[0]+5;
5803             }
5804         }
5805       else
5806         {
5807           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5808           ptI[1]=ptI[0]+ci[1]-ci[0];
5809           ptI++;
5810           *retPt++=i;
5811         }
5812     }
5813   _nodal_connec->decrRef();
5814   _nodal_connec=newConn.retn();
5815   _nodal_connec_index->decrRef();
5816   _nodal_connec_index=newConnI.retn();
5817   computeTypes();
5818   updateTime();
5819   return ret.retn();
5820 }
5821
5822 /*!
5823  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5824  * so that the number of cells remains the same. Quadratic faces are converted to
5825  * polygons. This method works only for 2D meshes in
5826  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5827  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5828  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5829  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5830  *         a polylinized edge constituting the input polygon.
5831  *  \throw If the coordinates array is not set.
5832  *  \throw If the nodal connectivity of cells is not defined.
5833  *  \throw If \a this->getMeshDimension() != 2.
5834  *  \throw If \a this->getSpaceDimension() != 2.
5835  */
5836 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5837 {
5838   checkFullyDefined();
5839   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
5840     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5841   double epsa=fabs(eps);
5842   if(epsa<std::numeric_limits<double>::min())
5843     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5844   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5845   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5846   revDesc1=0; revDescIndx1=0;
5847   mDesc->tessellate2D(eps);
5848   subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5849   setCoords(mDesc->getCoords());
5850 }
5851
5852 /*!
5853  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5854  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5855  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5856  *         a sub-divided edge.
5857  *  \throw If the coordinates array is not set.
5858  *  \throw If the nodal connectivity of cells is not defined.
5859  *  \throw If \a this->getMeshDimension() != 1.
5860  *  \throw If \a this->getSpaceDimension() != 2.
5861  */
5862 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5863 {
5864   checkFullyDefined();
5865   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5866     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5867   double epsa=fabs(eps);
5868   if(epsa<std::numeric_limits<double>::min())
5869     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal : epsilon is null ! Please specify a higher epsilon. If too tiny it can lead to a huge amount of nodes and memory !");
5870   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5871   int nbCells=getNumberOfCells();
5872   int nbNodes=getNumberOfNodes();
5873   const int *conn=_nodal_connec->getConstPointer();
5874   const int *connI=_nodal_connec_index->getConstPointer();
5875   const double *coords=_coords->getConstPointer();
5876   std::vector<double> addCoo;
5877   std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5878   MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5879   newConnI->alloc(nbCells+1,1);
5880   int *newConnIPtr=newConnI->getPointer();
5881   *newConnIPtr=0;
5882   int tmp1[3];
5883   INTERP_KERNEL::Node *tmp2[3];
5884   std::set<INTERP_KERNEL::NormalizedCellType> types;
5885   for(int i=0;i<nbCells;i++,newConnIPtr++)
5886     {
5887       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5888       if(cm.isQuadratic())
5889         {//assert(connI[i+1]-connI[i]-1==3)
5890           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5891           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5892           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5893           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5894           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5895           if(eac)
5896             {
5897               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5898               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5899               delete eac;
5900               newConnIPtr[1]=(int)newConn.size();
5901             }
5902           else
5903             {
5904               types.insert(INTERP_KERNEL::NORM_SEG2);
5905               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5906               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5907               newConnIPtr[1]=newConnIPtr[0]+3;
5908             }
5909         }
5910       else
5911         {
5912           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5913           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5914           newConnIPtr[1]=newConnIPtr[0]+3;
5915         }
5916     }
5917   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5918     return ;
5919   _types=types;
5920   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5921   MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5922   newConnArr->alloc((int)newConn.size(),1);
5923   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5924   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5925   MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5926   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5927   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5928   std::copy(addCoo.begin(),addCoo.end(),work);
5929   DataArrayDouble::SetArrayIn(newCoords,_coords);
5930   updateTime();
5931 }
5932
5933 /*!
5934  * This private method is used to subdivide edges of a mesh with meshdim==2. If \a this has no a meshdim equal to 2 an exception will be thrown.
5935  * This method completly ignore coordinates.
5936  * \param nodeSubdived is the nodal connectivity of subdivision of edges
5937  * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5938  * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5939  * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5940  */
5941 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5942 {
5943   checkFullyDefined();
5944   if(getMeshDimension()!=2)
5945     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5946   int nbOfCells=getNumberOfCells();
5947   int *connI=_nodal_connec_index->getPointer();
5948   int newConnLgth=0;
5949   for(int i=0;i<nbOfCells;i++,connI++)
5950     {
5951       int offset=descIndex[i];
5952       int nbOfEdges=descIndex[i+1]-offset;
5953       //
5954       bool ddirect=desc[offset+nbOfEdges-1]>0;
5955       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5956       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5957       for(int j=0;j<nbOfEdges;j++)
5958         {
5959           bool direct=desc[offset+j]>0;
5960           int edgeId=std::abs(desc[offset+j])-1;
5961           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5962             {
5963               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5964               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5965               int ref2=direct?id1:id2;
5966               if(ref==ref2)
5967                 {
5968                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5969                   newConnLgth+=nbOfSubNodes-1;
5970                   ref=direct?id2:id1;
5971                 }
5972               else
5973                 {
5974                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
5975                   throw INTERP_KERNEL::Exception(oss.str().c_str());
5976                 }
5977             }
5978           else
5979             {
5980               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
5981             }
5982         }
5983       newConnLgth++;//+1 is for cell type
5984       connI[1]=newConnLgth;
5985     }
5986   //
5987   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5988   newConn->alloc(newConnLgth,1);
5989   int *work=newConn->getPointer();
5990   for(int i=0;i<nbOfCells;i++)
5991     {
5992       *work++=INTERP_KERNEL::NORM_POLYGON;
5993       int offset=descIndex[i];
5994       int nbOfEdges=descIndex[i+1]-offset;
5995       for(int j=0;j<nbOfEdges;j++)
5996         {
5997           bool direct=desc[offset+j]>0;
5998           int edgeId=std::abs(desc[offset+j])-1;
5999           if(direct)
6000             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
6001           else
6002             {
6003               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6004               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6005               work=std::copy(it,it+nbOfSubNodes-1,work);
6006             }
6007         }
6008     }
6009   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6010   _types.clear();
6011   if(nbOfCells>0)
6012     _types.insert(INTERP_KERNEL::NORM_POLYGON);
6013 }
6014
6015 /*!
6016  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6017  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6018  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6019  * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6020  * so it can be useful to call mergeNodes() before calling this method.
6021  *  \throw If \a this->getMeshDimension() <= 1.
6022  *  \throw If the coordinates array is not set.
6023  *  \throw If the nodal connectivity of cells is not defined.
6024  */
6025 void MEDCouplingUMesh::convertDegeneratedCells()
6026 {
6027   checkFullyDefined();
6028   if(getMeshDimension()<=1)
6029     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6030   int nbOfCells=getNumberOfCells();
6031   if(nbOfCells<1)
6032     return ;
6033   int initMeshLgth=getNodalConnectivityArrayLen();
6034   int *conn=_nodal_connec->getPointer();
6035   int *index=_nodal_connec_index->getPointer();
6036   int posOfCurCell=0;
6037   int newPos=0;
6038   int lgthOfCurCell;
6039   for(int i=0;i<nbOfCells;i++)
6040     {
6041       lgthOfCurCell=index[i+1]-posOfCurCell;
6042       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6043       int newLgth;
6044       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6045                                                                                                      conn+newPos+1,newLgth);
6046       conn[newPos]=newType;
6047       newPos+=newLgth+1;
6048       posOfCurCell=index[i+1];
6049       index[i+1]=newPos;
6050     }
6051   if(newPos!=initMeshLgth)
6052     _nodal_connec->reAlloc(newPos);
6053   computeTypes();
6054 }
6055
6056 /*!
6057  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6058  * A cell is considered to be oriented correctly if an angle between its
6059  * normal vector and a given vector is less than \c PI / \c 2.
6060  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6061  *         cells. 
6062  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6063  *         checked.
6064  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6065  *         is not cleared before filling in.
6066  *  \throw If \a this->getMeshDimension() != 2.
6067  *  \throw If \a this->getSpaceDimension() != 3.
6068  *
6069  *  \if ENABLE_EXAMPLES
6070  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6071  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6072  *  \endif
6073  */
6074 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6075 {
6076   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6077     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6078   int nbOfCells=getNumberOfCells();
6079   const int *conn=_nodal_connec->getConstPointer();
6080   const int *connI=_nodal_connec_index->getConstPointer();
6081   const double *coordsPtr=_coords->getConstPointer();
6082   for(int i=0;i<nbOfCells;i++)
6083     {
6084       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6085       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6086         {
6087           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6088           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6089             cells.push_back(i);
6090         }
6091     }
6092 }
6093
6094 /*!
6095  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6096  * considered to be oriented correctly if an angle between its normal vector and a
6097  * given vector is less than \c PI / \c 2. 
6098  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6099  *         cells. 
6100  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6101  *         checked.
6102  *  \throw If \a this->getMeshDimension() != 2.
6103  *  \throw If \a this->getSpaceDimension() != 3.
6104  *
6105  *  \if ENABLE_EXAMPLES
6106  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6107  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6108  *  \endif
6109  *
6110  *  \sa changeOrientationOfCells
6111  */
6112 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6113 {
6114   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6115     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6116   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6117   const int *connI(_nodal_connec_index->getConstPointer());
6118   const double *coordsPtr(_coords->getConstPointer());
6119   bool isModified(false);
6120   for(int i=0;i<nbOfCells;i++)
6121     {
6122       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6123       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6124         {
6125           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6126           bool isQuadratic(cm.isQuadratic());
6127           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6128             {
6129               isModified=true;
6130               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6131             }
6132         }
6133     }
6134   if(isModified)
6135     _nodal_connec->declareAsNew();
6136   updateTime();
6137 }
6138
6139 /*!
6140  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6141  *
6142  * \sa orientCorrectly2DCells
6143  */
6144 void MEDCouplingUMesh::changeOrientationOfCells()
6145 {
6146   int mdim(getMeshDimension());
6147   if(mdim!=2 && mdim!=1)
6148     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6149   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6150   const int *connI(_nodal_connec_index->getConstPointer());
6151   if(mdim==2)
6152     {//2D
6153       for(int i=0;i<nbOfCells;i++)
6154         {
6155           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6156           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6157           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6158         }
6159     }
6160   else
6161     {//1D
6162       for(int i=0;i<nbOfCells;i++)
6163         {
6164           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6165           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6166           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6167         }
6168     }
6169 }
6170
6171 /*!
6172  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6173  * oriented facets. The normal vector of the facet should point out of the cell.
6174  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6175  *         is not cleared before filling in.
6176  *  \throw If \a this->getMeshDimension() != 3.
6177  *  \throw If \a this->getSpaceDimension() != 3.
6178  *  \throw If the coordinates array is not set.
6179  *  \throw If the nodal connectivity of cells is not defined.
6180  *
6181  *  \if ENABLE_EXAMPLES
6182  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6183  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6184  *  \endif
6185  */
6186 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6187 {
6188   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6189     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6190   int nbOfCells=getNumberOfCells();
6191   const int *conn=_nodal_connec->getConstPointer();
6192   const int *connI=_nodal_connec_index->getConstPointer();
6193   const double *coordsPtr=_coords->getConstPointer();
6194   for(int i=0;i<nbOfCells;i++)
6195     {
6196       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6197       if(type==INTERP_KERNEL::NORM_POLYHED)
6198         {
6199           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6200             cells.push_back(i);
6201         }
6202     }
6203 }
6204
6205 /*!
6206  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6207  * out of the cell. 
6208  *  \throw If \a this->getMeshDimension() != 3.
6209  *  \throw If \a this->getSpaceDimension() != 3.
6210  *  \throw If the coordinates array is not set.
6211  *  \throw If the nodal connectivity of cells is not defined.
6212  *  \throw If the reparation fails.
6213  *
6214  *  \if ENABLE_EXAMPLES
6215  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6216  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6217  *  \endif
6218  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6219  */
6220 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6221 {
6222   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6223     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6224   int nbOfCells=getNumberOfCells();
6225   int *conn=_nodal_connec->getPointer();
6226   const int *connI=_nodal_connec_index->getConstPointer();
6227   const double *coordsPtr=_coords->getConstPointer();
6228   for(int i=0;i<nbOfCells;i++)
6229     {
6230       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6231       if(type==INTERP_KERNEL::NORM_POLYHED)
6232         {
6233           try
6234           {
6235               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6236                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6237           }
6238           catch(INTERP_KERNEL::Exception& e)
6239           {
6240               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6241               throw INTERP_KERNEL::Exception(oss.str().c_str());
6242           }
6243         }
6244     }
6245   updateTime();
6246 }
6247
6248 /*!
6249  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6250  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6251  * according to which the first facet of the cell should be oriented to have the normal vector
6252  * pointing out of cell.
6253  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6254  *         cells. The caller is to delete this array using decrRef() as it is no more
6255  *         needed. 
6256  *  \throw If \a this->getMeshDimension() != 3.
6257  *  \throw If \a this->getSpaceDimension() != 3.
6258  *  \throw If the coordinates array is not set.
6259  *  \throw If the nodal connectivity of cells is not defined.
6260  *
6261  *  \if ENABLE_EXAMPLES
6262  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6263  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6264  *  \endif
6265  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6266  */
6267 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6268 {
6269   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6270   if(getMeshDimension()!=3)
6271     throw INTERP_KERNEL::Exception(msg);
6272   int spaceDim=getSpaceDimension();
6273   if(spaceDim!=3)
6274     throw INTERP_KERNEL::Exception(msg);
6275   //
6276   int nbOfCells=getNumberOfCells();
6277   int *conn=_nodal_connec->getPointer();
6278   const int *connI=_nodal_connec_index->getConstPointer();
6279   const double *coo=getCoords()->getConstPointer();
6280   MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6281   for(int i=0;i<nbOfCells;i++)
6282     {
6283       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6284       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6285         {
6286           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6287             {
6288               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6289               cells->pushBackSilent(i);
6290             }
6291         }
6292     }
6293   return cells.retn();
6294 }
6295
6296 /*!
6297  * This method is a faster method to correct orientation of all 3D cells in \a this.
6298  * 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.
6299  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6300  * 
6301  * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6302  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, 
6303  */
6304 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6305 {
6306   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6307     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6308   int nbOfCells=getNumberOfCells();
6309   int *conn=_nodal_connec->getPointer();
6310   const int *connI=_nodal_connec_index->getConstPointer();
6311   const double *coordsPtr=_coords->getConstPointer();
6312   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6313   for(int i=0;i<nbOfCells;i++)
6314     {
6315       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6316       switch(type)
6317       {
6318         case INTERP_KERNEL::NORM_TETRA4:
6319           {
6320             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6321               {
6322                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6323                 ret->pushBackSilent(i);
6324               }
6325             break;
6326           }
6327         case INTERP_KERNEL::NORM_PYRA5:
6328           {
6329             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6330               {
6331                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6332                 ret->pushBackSilent(i);
6333               }
6334             break;
6335           }
6336         case INTERP_KERNEL::NORM_PENTA6:
6337         case INTERP_KERNEL::NORM_HEXA8:
6338         case INTERP_KERNEL::NORM_HEXGP12:
6339           {
6340             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6341               {
6342                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6343                 ret->pushBackSilent(i);
6344               }
6345             break;
6346           }
6347         case INTERP_KERNEL::NORM_POLYHED:
6348           {
6349             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6350               {
6351                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6352                 ret->pushBackSilent(i);
6353               }
6354             break;
6355           }
6356         default:
6357           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 !");
6358       }
6359     }
6360   updateTime();
6361   return ret.retn();
6362 }
6363
6364 /*!
6365  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6366  * If it is not the case an exception will be thrown.
6367  * This method is fast because the first cell of \a this is used to compute the plane.
6368  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6369  * \param pos output of size at least 3 used to store a point owned of searched plane.
6370  */
6371 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6372 {
6373   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6374     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6375   const int *conn=_nodal_connec->getConstPointer();
6376   const int *connI=_nodal_connec_index->getConstPointer();
6377   const double *coordsPtr=_coords->getConstPointer();
6378   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6379   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6380 }
6381
6382 /*!
6383  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6384  * cells. Currently cells of the following types are treated:
6385  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6386  * For a cell of other type an exception is thrown.
6387  * Space dimension of a 2D mesh can be either 2 or 3.
6388  * The Edge Ratio of a cell \f$t\f$ is: 
6389  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
6390  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6391  *  the smallest edge lengths of \f$t\f$.
6392  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6393  *          cells and one time, lying on \a this mesh. The caller is to delete this
6394  *          field using decrRef() as it is no more needed. 
6395  *  \throw If the coordinates array is not set.
6396  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6397  *  \throw If the connectivity data array has more than one component.
6398  *  \throw If the connectivity data array has a named component.
6399  *  \throw If the connectivity index data array has more than one component.
6400  *  \throw If the connectivity index data array has a named component.
6401  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6402  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6403  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6404  */
6405 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6406 {
6407   checkConsistencyLight();
6408   int spaceDim=getSpaceDimension();
6409   int meshDim=getMeshDimension();
6410   if(spaceDim!=2 && spaceDim!=3)
6411     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6412   if(meshDim!=2 && meshDim!=3)
6413     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6414   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6415   ret->setMesh(this);
6416   int nbOfCells=getNumberOfCells();
6417   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6418   arr->alloc(nbOfCells,1);
6419   double *pt=arr->getPointer();
6420   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6421   const int *conn=_nodal_connec->getConstPointer();
6422   const int *connI=_nodal_connec_index->getConstPointer();
6423   const double *coo=_coords->getConstPointer();
6424   double tmp[12];
6425   for(int i=0;i<nbOfCells;i++,pt++)
6426     {
6427       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6428       switch(t)
6429       {
6430         case INTERP_KERNEL::NORM_TRI3:
6431           {
6432             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6433             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6434             break;
6435           }
6436         case INTERP_KERNEL::NORM_QUAD4:
6437           {
6438             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6439             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6440             break;
6441           }
6442         case INTERP_KERNEL::NORM_TETRA4:
6443           {
6444             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6445             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6446             break;
6447           }
6448         default:
6449           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6450       }
6451       conn+=connI[i+1]-connI[i];
6452     }
6453   ret->setName("EdgeRatio");
6454   ret->synchronizeTimeWithSupport();
6455   return ret.retn();
6456 }
6457
6458 /*!
6459  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6460  * cells. Currently cells of the following types are treated:
6461  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6462  * For a cell of other type an exception is thrown.
6463  * Space dimension of a 2D mesh can be either 2 or 3.
6464  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6465  *          cells and one time, lying on \a this mesh. The caller is to delete this
6466  *          field using decrRef() as it is no more needed. 
6467  *  \throw If the coordinates array is not set.
6468  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6469  *  \throw If the connectivity data array has more than one component.
6470  *  \throw If the connectivity data array has a named component.
6471  *  \throw If the connectivity index data array has more than one component.
6472  *  \throw If the connectivity index data array has a named component.
6473  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6474  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6475  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6476  */
6477 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6478 {
6479   checkConsistencyLight();
6480   int spaceDim=getSpaceDimension();
6481   int meshDim=getMeshDimension();
6482   if(spaceDim!=2 && spaceDim!=3)
6483     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6484   if(meshDim!=2 && meshDim!=3)
6485     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6486   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6487   ret->setMesh(this);
6488   int nbOfCells=getNumberOfCells();
6489   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6490   arr->alloc(nbOfCells,1);
6491   double *pt=arr->getPointer();
6492   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6493   const int *conn=_nodal_connec->getConstPointer();
6494   const int *connI=_nodal_connec_index->getConstPointer();
6495   const double *coo=_coords->getConstPointer();
6496   double tmp[12];
6497   for(int i=0;i<nbOfCells;i++,pt++)
6498     {
6499       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6500       switch(t)
6501       {
6502         case INTERP_KERNEL::NORM_TRI3:
6503           {
6504             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6505             *pt=INTERP_KERNEL::triAspectRatio(tmp);
6506             break;
6507           }
6508         case INTERP_KERNEL::NORM_QUAD4:
6509           {
6510             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6511             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6512             break;
6513           }
6514         case INTERP_KERNEL::NORM_TETRA4:
6515           {
6516             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6517             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6518             break;
6519           }
6520         default:
6521           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6522       }
6523       conn+=connI[i+1]-connI[i];
6524     }
6525   ret->setName("AspectRatio");
6526   ret->synchronizeTimeWithSupport();
6527   return ret.retn();
6528 }
6529
6530 /*!
6531  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6532  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6533  * in 3D space. Currently only cells of the following types are
6534  * treated: INTERP_KERNEL::NORM_QUAD4.
6535  * For a cell of other type an exception is thrown.
6536  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6537  * Defining
6538  * \f$t=\vec{da}\times\vec{ab}\f$,
6539  * \f$u=\vec{ab}\times\vec{bc}\f$
6540  * \f$v=\vec{bc}\times\vec{cd}\f$
6541  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6542  *  \f[
6543  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6544  *  \f]
6545  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6546  *          cells and one time, lying on \a this mesh. The caller is to delete this
6547  *          field using decrRef() as it is no more needed. 
6548  *  \throw If the coordinates array is not set.
6549  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6550  *  \throw If the connectivity data array has more than one component.
6551  *  \throw If the connectivity data array has a named component.
6552  *  \throw If the connectivity index data array has more than one component.
6553  *  \throw If the connectivity index data array has a named component.
6554  *  \throw If \a this->getMeshDimension() != 2.
6555  *  \throw If \a this->getSpaceDimension() != 3.
6556  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6557  */
6558 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6559 {
6560   checkConsistencyLight();
6561   int spaceDim=getSpaceDimension();
6562   int meshDim=getMeshDimension();
6563   if(spaceDim!=3)
6564     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6565   if(meshDim!=2)
6566     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6567   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6568   ret->setMesh(this);
6569   int nbOfCells=getNumberOfCells();
6570   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6571   arr->alloc(nbOfCells,1);
6572   double *pt=arr->getPointer();
6573   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6574   const int *conn=_nodal_connec->getConstPointer();
6575   const int *connI=_nodal_connec_index->getConstPointer();
6576   const double *coo=_coords->getConstPointer();
6577   double tmp[12];
6578   for(int i=0;i<nbOfCells;i++,pt++)
6579     {
6580       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6581       switch(t)
6582       {
6583         case INTERP_KERNEL::NORM_QUAD4:
6584           {
6585             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6586             *pt=INTERP_KERNEL::quadWarp(tmp);
6587             break;
6588           }
6589         default:
6590           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6591       }
6592       conn+=connI[i+1]-connI[i];
6593     }
6594   ret->setName("Warp");
6595   ret->synchronizeTimeWithSupport();
6596   return ret.retn();
6597 }
6598
6599
6600 /*!
6601  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6602  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6603  * treated: INTERP_KERNEL::NORM_QUAD4.
6604  * The skew is computed as follow for a quad with points (a,b,c,d): let
6605  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6606  * then the skew is computed as:
6607  *  \f[
6608  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6609  *  \f]
6610  *
6611  * For a cell of other type an exception is thrown.
6612  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6613  *          cells and one time, lying on \a this mesh. The caller is to delete this
6614  *          field using decrRef() as it is no more needed. 
6615  *  \throw If the coordinates array is not set.
6616  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6617  *  \throw If the connectivity data array has more than one component.
6618  *  \throw If the connectivity data array has a named component.
6619  *  \throw If the connectivity index data array has more than one component.
6620  *  \throw If the connectivity index data array has a named component.
6621  *  \throw If \a this->getMeshDimension() != 2.
6622  *  \throw If \a this->getSpaceDimension() != 3.
6623  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6624  */
6625 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6626 {
6627   checkConsistencyLight();
6628   int spaceDim=getSpaceDimension();
6629   int meshDim=getMeshDimension();
6630   if(spaceDim!=3)
6631     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6632   if(meshDim!=2)
6633     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6634   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6635   ret->setMesh(this);
6636   int nbOfCells=getNumberOfCells();
6637   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6638   arr->alloc(nbOfCells,1);
6639   double *pt=arr->getPointer();
6640   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6641   const int *conn=_nodal_connec->getConstPointer();
6642   const int *connI=_nodal_connec_index->getConstPointer();
6643   const double *coo=_coords->getConstPointer();
6644   double tmp[12];
6645   for(int i=0;i<nbOfCells;i++,pt++)
6646     {
6647       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6648       switch(t)
6649       {
6650         case INTERP_KERNEL::NORM_QUAD4:
6651           {
6652             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6653             *pt=INTERP_KERNEL::quadSkew(tmp);
6654             break;
6655           }
6656         default:
6657           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6658       }
6659       conn+=connI[i+1]-connI[i];
6660     }
6661   ret->setName("Skew");
6662   ret->synchronizeTimeWithSupport();
6663   return ret.retn();
6664 }
6665
6666 /*!
6667  * 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.
6668  *
6669  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6670  *
6671  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6672  */
6673 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6674 {
6675   checkConsistencyLight();
6676   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6677   ret->setMesh(this);
6678   std::set<INTERP_KERNEL::NormalizedCellType> types;
6679   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6680   int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6681   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6682   arr->alloc(nbCells,1);
6683   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6684     {
6685       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6686       MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6687       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6688     }
6689   ret->setArray(arr);
6690   ret->setName("Diameter");
6691   return ret.retn();
6692 }
6693
6694 /*!
6695  * This method aggregate the bbox of each cell and put it into bbox parameter.
6696  * 
6697  * \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)
6698  *                         For all other cases this input parameter is ignored.
6699  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6700  * 
6701  * \throw If \a this is not fully set (coordinates and connectivity).
6702  * \throw If a cell in \a this has no valid nodeId.
6703  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6704  */
6705 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6706 {
6707   int mDim(getMeshDimension()),sDim(getSpaceDimension());
6708   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.
6709     return getBoundingBoxForBBTreeFast();
6710   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6711     {
6712       bool presenceOfQuadratic(false);
6713       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6714         {
6715           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6716           if(cm.isQuadratic())
6717             presenceOfQuadratic=true;
6718         }
6719       if(!presenceOfQuadratic)
6720         return getBoundingBoxForBBTreeFast();
6721       if(mDim==2 && sDim==2)
6722         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6723       else
6724         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6725     }
6726   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) !");
6727 }
6728
6729 /*!
6730  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6731  * So meshes having quadratic cells the computed bounding boxes can be invalid !
6732  * 
6733  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6734  * 
6735  * \throw If \a this is not fully set (coordinates and connectivity).
6736  * \throw If a cell in \a this has no valid nodeId.
6737  */
6738 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6739 {
6740   checkFullyDefined();
6741   int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6742   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6743   double *bbox(ret->getPointer());
6744   for(int i=0;i<nbOfCells*spaceDim;i++)
6745     {
6746       bbox[2*i]=std::numeric_limits<double>::max();
6747       bbox[2*i+1]=-std::numeric_limits<double>::max();
6748     }
6749   const double *coordsPtr(_coords->getConstPointer());
6750   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6751   for(int i=0;i<nbOfCells;i++)
6752     {
6753       int offset=connI[i]+1;
6754       int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6755       for(int j=0;j<nbOfNodesForCell;j++)
6756         {
6757           int nodeId=conn[offset+j];
6758           if(nodeId>=0 && nodeId<nbOfNodes)
6759             {
6760               for(int k=0;k<spaceDim;k++)
6761                 {
6762                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6763                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6764                 }
6765               kk++;
6766             }
6767         }
6768       if(kk==0)
6769         {
6770           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6771           throw INTERP_KERNEL::Exception(oss.str().c_str());
6772         }
6773     }
6774   return ret.retn();
6775 }
6776
6777 /*!
6778  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6779  * useful for 2D meshes having quadratic cells
6780  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6781  * the two extremities of the arc of circle).
6782  * 
6783  * \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)
6784  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6785  * \throw If \a this is not fully defined.
6786  * \throw If \a this is not a mesh with meshDimension equal to 2.
6787  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6788  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6789  */
6790 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6791 {
6792   checkFullyDefined();
6793   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6794   if(spaceDim!=2 || mDim!=2)
6795     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!");
6796   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6797   double *bbox(ret->getPointer());
6798   const double *coords(_coords->getConstPointer());
6799   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6800   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6801     {
6802       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6803       int sz(connI[1]-connI[0]-1);
6804       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6805       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6806       INTERP_KERNEL::QuadraticPolygon *pol(0);
6807       for(int j=0;j<sz;j++)
6808         {
6809           int nodeId(conn[*connI+1+j]);
6810           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6811         }
6812       if(!cm.isQuadratic())
6813         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6814       else
6815         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6816       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6817       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); 
6818     }
6819   return ret.retn();
6820 }
6821
6822 /*!
6823  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6824  * useful for 2D meshes having quadratic cells
6825  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6826  * the two extremities of the arc of circle).
6827  * 
6828  * \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)
6829  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6830  * \throw If \a this is not fully defined.
6831  * \throw If \a this is not a mesh with meshDimension equal to 1.
6832  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6833  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6834  */
6835 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6836 {
6837   checkFullyDefined();
6838   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6839   if(spaceDim!=2 || mDim!=1)
6840     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!");
6841   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6842   double *bbox(ret->getPointer());
6843   const double *coords(_coords->getConstPointer());
6844   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6845   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6846     {
6847       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6848       int sz(connI[1]-connI[0]-1);
6849       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6850       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6851       INTERP_KERNEL::Edge *edge(0);
6852       for(int j=0;j<sz;j++)
6853         {
6854           int nodeId(conn[*connI+1+j]);
6855           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6856         }
6857       if(!cm.isQuadratic())
6858         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6859       else
6860         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6861       const INTERP_KERNEL::Bounds& b(edge->getBounds());
6862       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6863     }
6864   return ret.retn();
6865 }
6866
6867 /// @cond INTERNAL
6868
6869 namespace MEDCouplingImpl
6870 {
6871   class ConnReader
6872   {
6873   public:
6874     ConnReader(const int *c, int val):_conn(c),_val(val) { }
6875     bool operator() (const int& pos) { return _conn[pos]!=_val; }
6876   private:
6877     const int *_conn;
6878     int _val;
6879   };
6880
6881   class ConnReader2
6882   {
6883   public:
6884     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6885     bool operator() (const int& pos) { return _conn[pos]==_val; }
6886   private:
6887     const int *_conn;
6888     int _val;
6889   };
6890 }
6891
6892 /// @endcond
6893
6894 /*!
6895  * This method expects that \a this is sorted by types. If not an exception will be thrown.
6896  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6897  * \a this is composed in cell types.
6898  * The returned array is of size 3*n where n is the number of different types present in \a this. 
6899  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here. 
6900  * This parameter is kept only for compatibility with other methode listed above.
6901  */
6902 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6903 {
6904   checkConnectivityFullyDefined();
6905   const int *conn=_nodal_connec->getConstPointer();
6906   const int *connI=_nodal_connec_index->getConstPointer();
6907   const int *work=connI;
6908   int nbOfCells=getNumberOfCells();
6909   std::size_t n=getAllGeoTypes().size();
6910   std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6911   std::set<INTERP_KERNEL::NormalizedCellType> types;
6912   for(std::size_t i=0;work!=connI+nbOfCells;i++)
6913     {
6914       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6915       if(types.find(typ)!=types.end())
6916         {
6917           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6918           oss << " is not contiguous !";
6919           throw INTERP_KERNEL::Exception(oss.str().c_str());
6920         }
6921       types.insert(typ);
6922       ret[3*i]=typ;
6923       const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6924       ret[3*i+1]=(int)std::distance(work,work2);
6925       work=work2;
6926     }
6927   return ret;
6928 }
6929
6930 /*!
6931  * This method is used to check that this has contiguous cell type in same order than described in \a code.
6932  * only for types cell, type node is not managed.
6933  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6934  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6935  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6936  * If 2 or more same geometric type is in \a code and exception is thrown too.
6937  *
6938  * This method firstly checks
6939  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6940  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6941  * an exception is thrown too.
6942  * 
6943  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6944  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown 
6945  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6946  */
6947 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6948 {
6949   if(code.empty())
6950     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6951   std::size_t sz=code.size();
6952   std::size_t n=sz/3;
6953   if(sz%3!=0)
6954     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6955   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6956   int nb=0;
6957   bool isNoPflUsed=true;
6958   for(std::size_t i=0;i<n;i++)
6959     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6960       {
6961         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6962         nb+=code[3*i+1];
6963         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6964           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6965         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6966       }
6967   if(types.size()!=n)
6968     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6969   if(isNoPflUsed)
6970     {
6971       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6972         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6973       if(types.size()==_types.size())
6974         return 0;
6975     }
6976   MCAuto<DataArrayInt> ret=DataArrayInt::New();
6977   ret->alloc(nb,1);
6978   int *retPtr=ret->getPointer();
6979   const int *connI=_nodal_connec_index->getConstPointer();
6980   const int *conn=_nodal_connec->getConstPointer();
6981   int nbOfCells=getNumberOfCells();
6982   const int *i=connI;
6983   int kk=0;
6984   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6985     {
6986       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
6987       int offset=(int)std::distance(connI,i);
6988       const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
6989       int nbOfCellsOfCurType=(int)std::distance(i,j);
6990       if(code[3*kk+2]==-1)
6991         for(int k=0;k<nbOfCellsOfCurType;k++)
6992           *retPtr++=k+offset;
6993       else
6994         {
6995           int idInIdsPerType=code[3*kk+2];
6996           if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
6997             {
6998               const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
6999               if(zePfl)
7000                 {
7001                   zePfl->checkAllocated();
7002                   if(zePfl->getNumberOfComponents()==1)
7003                     {
7004                       for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7005                         {
7006                           if(*k>=0 && *k<nbOfCellsOfCurType)
7007                             *retPtr=(*k)+offset;
7008                           else
7009                             {
7010                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7011                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7012                               throw INTERP_KERNEL::Exception(oss.str().c_str());
7013                             }
7014                         }
7015                     }
7016                   else
7017                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7018                 }
7019               else
7020                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7021             }
7022           else
7023             {
7024               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7025               oss << " should be in [0," << idsPerType.size() << ") !";
7026               throw INTERP_KERNEL::Exception(oss.str().c_str());
7027             }
7028         }
7029       i=j;
7030     }
7031   return ret.retn();
7032 }
7033
7034 /*!
7035  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7036  * 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.
7037  * 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.
7038  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7039  * 
7040  * \param [in] profile
7041  * \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.
7042  * \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,
7043  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7044  * \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.
7045  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7046  * \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
7047  */
7048 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7049 {
7050   if(!profile)
7051     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7052   if(profile->getNumberOfComponents()!=1)
7053     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7054   checkConnectivityFullyDefined();
7055   const int *conn=_nodal_connec->getConstPointer();
7056   const int *connI=_nodal_connec_index->getConstPointer();
7057   int nbOfCells=getNumberOfCells();
7058   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7059   std::vector<int> typeRangeVals(1);
7060   for(const int *i=connI;i!=connI+nbOfCells;)
7061     {
7062       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7063       if(std::find(types.begin(),types.end(),curType)!=types.end())
7064         {
7065           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7066         }
7067       types.push_back(curType);
7068       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7069       typeRangeVals.push_back((int)std::distance(connI,i));
7070     }
7071   //
7072   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7073   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7074   MCAuto<DataArrayInt> tmp0=castArr;
7075   MCAuto<DataArrayInt> tmp1=rankInsideCast;
7076   MCAuto<DataArrayInt> tmp2=castsPresent;
7077   //
7078   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7079   code.resize(3*nbOfCastsFinal);
7080   std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7081   std::vector< MCAuto<DataArrayInt> > idsPerType2;
7082   for(int i=0;i<nbOfCastsFinal;i++)
7083     {
7084       int castId=castsPresent->getIJ(i,0);
7085       MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7086       idsInPflPerType2.push_back(tmp3);
7087       code[3*i]=(int)types[castId];
7088       code[3*i+1]=tmp3->getNumberOfTuples();
7089       MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7090       if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7091         {
7092           tmp4->copyStringInfoFrom(*profile);
7093           idsPerType2.push_back(tmp4);
7094           code[3*i+2]=(int)idsPerType2.size()-1;
7095         }
7096       else
7097         {
7098           code[3*i+2]=-1;
7099         }
7100     }
7101   std::size_t sz2=idsInPflPerType2.size();
7102   idsInPflPerType.resize(sz2);
7103   for(std::size_t i=0;i<sz2;i++)
7104     {
7105       DataArrayInt *locDa=idsInPflPerType2[i];
7106       locDa->incrRef();
7107       idsInPflPerType[i]=locDa;
7108     }
7109   std::size_t sz=idsPerType2.size();
7110   idsPerType.resize(sz);
7111   for(std::size_t i=0;i<sz;i++)
7112     {
7113       DataArrayInt *locDa=idsPerType2[i];
7114       locDa->incrRef();
7115       idsPerType[i]=locDa;
7116     }
7117 }
7118
7119 /*!
7120  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7121  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7122  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7123  * 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.
7124  */
7125 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7126 {
7127   checkFullyDefined();
7128   nM1LevMesh->checkFullyDefined();
7129   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7130     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7131   if(_coords!=nM1LevMesh->getCoords())
7132     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7133   MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7134   MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7135   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7136   MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7137   desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7138   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7139   tmp->setConnectivity(tmp0,tmp1);
7140   tmp->renumberCells(ret0->getConstPointer(),false);
7141   revDesc=tmp->getNodalConnectivity();
7142   revDescIndx=tmp->getNodalConnectivityIndex();
7143   DataArrayInt *ret=0;
7144   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7145     {
7146       int tmp2;
7147       ret->getMaxValue(tmp2);
7148       ret->decrRef();
7149       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7150       throw INTERP_KERNEL::Exception(oss.str().c_str());
7151     }
7152   nM1LevMeshIds=ret;
7153   //
7154   revDesc->incrRef();
7155   revDescIndx->incrRef();
7156   ret1->incrRef();
7157   ret0->incrRef();
7158   meshnM1Old2New=ret0;
7159   return ret1;
7160 }
7161
7162 /*!
7163  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7164  * necessary for writing the mesh to MED file. Additionally returns a permutation array
7165  * in "Old to New" mode.
7166  *  \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7167  *          this array using decrRef() as it is no more needed.
7168  *  \throw If the nodal connectivity of cells is not defined.
7169  */
7170 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7171 {
7172   checkConnectivityFullyDefined();
7173   MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7174   renumberCells(ret->getConstPointer(),false);
7175   return ret.retn();
7176 }
7177
7178 /*!
7179  * This methods checks that cells are sorted by their types.
7180  * This method makes asumption (no check) that connectivity is correctly set before calling.
7181  */
7182 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7183 {
7184   checkFullyDefined();
7185   const int *conn=_nodal_connec->getConstPointer();
7186   const int *connI=_nodal_connec_index->getConstPointer();
7187   int nbOfCells=getNumberOfCells();
7188   std::set<INTERP_KERNEL::NormalizedCellType> types;
7189   for(const int *i=connI;i!=connI+nbOfCells;)
7190     {
7191       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7192       if(types.find(curType)!=types.end())
7193         return false;
7194       types.insert(curType);
7195       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7196     }
7197   return true;
7198 }
7199
7200 /*!
7201  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7202  * The geometric type order is specified by MED file.
7203  * 
7204  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7205  */
7206 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7207 {
7208   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7209 }
7210
7211 /*!
7212  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7213  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7214  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7215  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7216  */
7217 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7218 {
7219   checkFullyDefined();
7220   const int *conn=_nodal_connec->getConstPointer();
7221   const int *connI=_nodal_connec_index->getConstPointer();
7222   int nbOfCells=getNumberOfCells();
7223   if(nbOfCells==0)
7224     return true;
7225   int lastPos=-1;
7226   std::set<INTERP_KERNEL::NormalizedCellType> sg;
7227   for(const int *i=connI;i!=connI+nbOfCells;)
7228     {
7229       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7230       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7231       if(isTypeExists!=orderEnd)
7232         {
7233           int pos=(int)std::distance(orderBg,isTypeExists);
7234           if(pos<=lastPos)
7235             return false;
7236           lastPos=pos;
7237           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7238         }
7239       else
7240         {
7241           if(sg.find(curType)==sg.end())
7242             {
7243               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7244               sg.insert(curType);
7245             }
7246           else
7247             return false;
7248         }
7249     }
7250   return true;
7251 }
7252
7253 /*!
7254  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7255  * 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
7256  * number of tuples than input type array and with one component. This 2nd output array gives type by type the number of occurence of type in 'this'.
7257  */
7258 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7259 {
7260   checkConnectivityFullyDefined();
7261   int nbOfCells=getNumberOfCells();
7262   const int *conn=_nodal_connec->getConstPointer();
7263   const int *connI=_nodal_connec_index->getConstPointer();
7264   MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7265   MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7266   tmpa->alloc(nbOfCells,1);
7267   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7268   tmpb->fillWithZero();
7269   int *tmp=tmpa->getPointer();
7270   int *tmp2=tmpb->getPointer();
7271   for(const int *i=connI;i!=connI+nbOfCells;i++)
7272     {
7273       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7274       if(where!=orderEnd)
7275         {
7276           int pos=(int)std::distance(orderBg,where);
7277           tmp2[pos]++;
7278           tmp[std::distance(connI,i)]=pos;
7279         }
7280       else
7281         {
7282           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7283           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7284           oss << " has a type " << cm.getRepr() << " not in input array of type !";
7285           throw INTERP_KERNEL::Exception(oss.str().c_str());
7286         }
7287     }
7288   nbPerType=tmpb.retn();
7289   return tmpa.retn();
7290 }
7291
7292 /*!
7293  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7294  *
7295  * \return a new object containing the old to new correspondance.
7296  *
7297  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7298  */
7299 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7300 {
7301   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7302 }
7303
7304 /*!
7305  * This method is similar to method MEDCouplingUMesh::rearrange2ConsecutiveCellTypes except that the type order is specfied by [ \a orderBg , \a orderEnd ) (as MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method) and that this method is \b const and performs \b NO permutation in \a this.
7306  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7307  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7308  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7309  */
7310 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7311 {
7312   DataArrayInt *nbPerType=0;
7313   MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7314   nbPerType->decrRef();
7315   return tmpa->buildPermArrPerLevel();
7316 }
7317
7318 /*!
7319  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7320  * The number of cells remains unchanged after the call of this method.
7321  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7322  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7323  *
7324  * \return the array giving the correspondance old to new.
7325  */
7326 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7327 {
7328   checkFullyDefined();
7329   computeTypes();
7330   const int *conn=_nodal_connec->getConstPointer();
7331   const int *connI=_nodal_connec_index->getConstPointer();
7332   int nbOfCells=getNumberOfCells();
7333   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7334   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7335     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7336       {
7337         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7338         types.push_back(curType);
7339         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7340       }
7341   DataArrayInt *ret=DataArrayInt::New();
7342   ret->alloc(nbOfCells,1);
7343   int *retPtr=ret->getPointer();
7344   std::fill(retPtr,retPtr+nbOfCells,-1);
7345   int newCellId=0;
7346   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7347     {
7348       for(const int *i=connI;i!=connI+nbOfCells;i++)
7349         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7350           retPtr[std::distance(connI,i)]=newCellId++;
7351     }
7352   renumberCells(retPtr,false);
7353   return ret;
7354 }
7355
7356 /*!
7357  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7358  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7359  * This method makes asumption that connectivity is correctly set before calling.
7360  */
7361 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7362 {
7363   checkConnectivityFullyDefined();
7364   const int *conn=_nodal_connec->getConstPointer();
7365   const int *connI=_nodal_connec_index->getConstPointer();
7366   int nbOfCells=getNumberOfCells();
7367   std::vector<MEDCouplingUMesh *> ret;
7368   for(const int *i=connI;i!=connI+nbOfCells;)
7369     {
7370       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7371       int beginCellId=(int)std::distance(connI,i);
7372       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7373       int endCellId=(int)std::distance(connI,i);
7374       int sz=endCellId-beginCellId;
7375       int *cells=new int[sz];
7376       for(int j=0;j<sz;j++)
7377         cells[j]=beginCellId+j;
7378       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7379       delete [] cells;
7380       ret.push_back(m);
7381     }
7382   return ret;
7383 }
7384
7385 /*!
7386  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7387  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7388  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7389  *
7390  * \return a newly allocated instance, that the caller must manage.
7391  * \throw If \a this contains more than one geometric type.
7392  * \throw If the nodal connectivity of \a this is not fully defined.
7393  * \throw If the internal data is not coherent.
7394  */
7395 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7396 {
7397   checkConnectivityFullyDefined();
7398   if(_types.size()!=1)
7399     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7400   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7401   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7402   ret->setCoords(getCoords());
7403   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7404   if(retC)
7405     {
7406       MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7407       retC->setNodalConnectivity(c);
7408     }
7409   else
7410     {
7411       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7412       if(!retD)
7413         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7414       DataArrayInt *c=0,*ci=0;
7415       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7416       MCAuto<DataArrayInt> cs(c),cis(ci);
7417       retD->setNodalConnectivity(cs,cis);
7418     }
7419   return ret.retn();
7420 }
7421
7422 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7423 {
7424   checkConnectivityFullyDefined();
7425   if(_types.size()!=1)
7426     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7427   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7428   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7429   if(cm.isDynamic())
7430     {
7431       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7432       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7433       throw INTERP_KERNEL::Exception(oss.str().c_str());
7434     }
7435   int nbCells=getNumberOfCells();
7436   int typi=(int)typ;
7437   int nbNodesPerCell=(int)cm.getNumberOfNodes();
7438   MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7439   int *outPtr=connOut->getPointer();
7440   const int *conn=_nodal_connec->begin();
7441   const int *connI=_nodal_connec_index->begin();
7442   nbNodesPerCell++;
7443   for(int i=0;i<nbCells;i++,connI++)
7444     {
7445       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7446         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7447       else
7448         {
7449           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 << ") !";
7450           throw INTERP_KERNEL::Exception(oss.str().c_str());
7451         }
7452     }
7453   return connOut.retn();
7454 }
7455
7456 /*!
7457  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7458  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7459  * \param nodalConn
7460  * \param nodalConnI
7461  */
7462 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7463 {
7464   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7465   checkConnectivityFullyDefined();
7466   if(_types.size()!=1)
7467     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7468   int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7469   if(lgth<nbCells)
7470     throw INTERP_KERNEL::Exception(msg0);
7471   MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7472   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7473   int *cp(c->getPointer()),*cip(ci->getPointer());
7474   const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7475   cip[0]=0;
7476   for(int i=0;i<nbCells;i++,cip++,incip++)
7477     {
7478       int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7479       int delta(stop-strt);
7480       if(delta>=1)
7481         {
7482           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7483             cp=std::copy(incp+strt,incp+stop,cp);
7484           else
7485             throw INTERP_KERNEL::Exception(msg0);
7486         }
7487       else
7488         throw INTERP_KERNEL::Exception(msg0);
7489       cip[1]=cip[0]+delta;
7490     }
7491   nodalConn=c.retn(); nodalConnIndex=ci.retn();
7492 }
7493
7494 /*!
7495  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7496  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7497  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7498  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7499  * are not used here to avoid the build of big permutation array.
7500  *
7501  * \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
7502  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7503  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7504  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7505  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7506  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
7507  * \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
7508  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7509  */
7510 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7511                                                                             DataArrayInt *&szOfCellGrpOfSameType,
7512                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType)
7513 {
7514   std::vector<const MEDCouplingUMesh *> ms2;
7515   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7516     if(*it)
7517       {
7518         (*it)->checkConnectivityFullyDefined();
7519         ms2.push_back(*it);
7520       }
7521   if(ms2.empty())
7522     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7523   const DataArrayDouble *refCoo=ms2[0]->getCoords();
7524   int meshDim=ms2[0]->getMeshDimension();
7525   std::vector<const MEDCouplingUMesh *> m1ssm;
7526   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7527   //
7528   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7529   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7530   int fake=0,rk=0;
7531   MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7532   ret1->alloc(0,1); ret2->alloc(0,1);
7533   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7534     {
7535       if(meshDim!=(*it)->getMeshDimension())
7536         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7537       if(refCoo!=(*it)->getCoords())
7538         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7539       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7540       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7541       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7542       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7543         {
7544           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7545           m1ssmSingleAuto.push_back(singleCell);
7546           m1ssmSingle.push_back(singleCell);
7547           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7548         }
7549     }
7550   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7551   MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7552   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7553   for(std::size_t i=0;i<m1ssm.size();i++)
7554     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7555   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7556   szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7557   idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7558   return ret0.retn();
7559 }
7560
7561 /*!
7562  * This method returns a newly created DataArrayInt instance.
7563  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7564  */
7565 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7566 {
7567   checkFullyDefined();
7568   const int *conn=_nodal_connec->getConstPointer();
7569   const int *connIndex=_nodal_connec_index->getConstPointer();
7570   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7571   for(const int *w=begin;w!=end;w++)
7572     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7573       ret->pushBackSilent(*w);
7574   return ret.retn();
7575 }
7576
7577 /*!
7578  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7579  * are in [0:getNumberOfCells())
7580  */
7581 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7582 {
7583   checkFullyDefined();
7584   const int *conn=_nodal_connec->getConstPointer();
7585   const int *connI=_nodal_connec_index->getConstPointer();
7586   int nbOfCells=getNumberOfCells();
7587   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7588   int *tmp=new int[nbOfCells];
7589   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7590     {
7591       int j=0;
7592       for(const int *i=connI;i!=connI+nbOfCells;i++)
7593         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7594           tmp[std::distance(connI,i)]=j++;
7595     }
7596   DataArrayInt *ret=DataArrayInt::New();
7597   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7598   ret->copyStringInfoFrom(*da);
7599   int *retPtr=ret->getPointer();
7600   const int *daPtr=da->getConstPointer();
7601   int nbOfElems=da->getNbOfElems();
7602   for(int k=0;k<nbOfElems;k++)
7603     retPtr[k]=tmp[daPtr[k]];
7604   delete [] tmp;
7605   return ret;
7606 }
7607
7608 /*!
7609  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7610  * This method \b works \b for mesh sorted by type.
7611  * cells whose ids is in 'idsPerGeoType' array.
7612  * This method conserves coords and name of mesh.
7613  */
7614 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7615 {
7616   std::vector<int> code=getDistributionOfTypes();
7617   std::size_t nOfTypesInThis=code.size()/3;
7618   int sz=0,szOfType=0;
7619   for(std::size_t i=0;i<nOfTypesInThis;i++)
7620     {
7621       if(code[3*i]!=type)
7622         sz+=code[3*i+1];
7623       else
7624         szOfType=code[3*i+1];
7625     }
7626   for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7627     if(*work<0 || *work>=szOfType)
7628       {
7629         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7630         oss << ". It should be in [0," << szOfType << ") !";
7631         throw INTERP_KERNEL::Exception(oss.str().c_str());
7632       }
7633   MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7634   int *idsPtr=idsTokeep->getPointer();
7635   int offset=0;
7636   for(std::size_t i=0;i<nOfTypesInThis;i++)
7637     {
7638       if(code[3*i]!=type)
7639         for(int j=0;j<code[3*i+1];j++)
7640           *idsPtr++=offset+j;
7641       else
7642         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7643       offset+=code[3*i+1];
7644     }
7645   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7646   ret->copyTinyInfoFrom(this);
7647   return ret.retn();
7648 }
7649
7650 /*!
7651  * This method returns a vector of size 'this->getNumberOfCells()'.
7652  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7653  */
7654 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7655 {
7656   int ncell=getNumberOfCells();
7657   std::vector<bool> ret(ncell);
7658   const int *cI=getNodalConnectivityIndex()->getConstPointer();
7659   const int *c=getNodalConnectivity()->getConstPointer();
7660   for(int i=0;i<ncell;i++)
7661     {
7662       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7663       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7664       ret[i]=cm.isQuadratic();
7665     }
7666   return ret;
7667 }
7668
7669 /*!
7670  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7671  */
7672 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7673 {
7674   if(other->getType()!=UNSTRUCTURED)
7675     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7676   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7677   return MergeUMeshes(this,otherC);
7678 }
7679
7680 /*!
7681  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7682  * computed by averaging coordinates of cell nodes, so this method is not a right
7683  * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7684  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7685  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7686  *          components. The caller is to delete this array using decrRef() as it is
7687  *          no more needed.
7688  *  \throw If the coordinates array is not set.
7689  *  \throw If the nodal connectivity of cells is not defined.
7690  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7691  */
7692 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7693 {
7694   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7695   int spaceDim=getSpaceDimension();
7696   int nbOfCells=getNumberOfCells();
7697   ret->alloc(nbOfCells,spaceDim);
7698   ret->copyStringInfoFrom(*getCoords());
7699   double *ptToFill=ret->getPointer();
7700   const int *nodal=_nodal_connec->getConstPointer();
7701   const int *nodalI=_nodal_connec_index->getConstPointer();
7702   const double *coor=_coords->getConstPointer();
7703   for(int i=0;i<nbOfCells;i++)
7704     {
7705       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7706       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7707       ptToFill+=spaceDim;
7708     }
7709   return ret.retn();
7710 }
7711
7712 /*!
7713  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7714  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the 
7715  * 
7716  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned 
7717  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7718  * 
7719  * \sa MEDCouplingUMesh::computeCellCenterOfMass
7720  * \throw If \a this is not fully defined (coordinates and connectivity)
7721  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7722  */
7723 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7724 {
7725   checkFullyDefined();
7726   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7727   int spaceDim=getSpaceDimension();
7728   int nbOfCells=getNumberOfCells();
7729   int nbOfNodes=getNumberOfNodes();
7730   ret->alloc(nbOfCells,spaceDim);
7731   double *ptToFill=ret->getPointer();
7732   const int *nodal=_nodal_connec->getConstPointer();
7733   const int *nodalI=_nodal_connec_index->getConstPointer();
7734   const double *coor=_coords->getConstPointer();
7735   for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7736     {
7737       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7738       std::fill(ptToFill,ptToFill+spaceDim,0.);
7739       if(type!=INTERP_KERNEL::NORM_POLYHED)
7740         {
7741           for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7742             {
7743               if(*conn>=0 && *conn<nbOfNodes)
7744                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7745               else
7746                 {
7747                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
7748                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7749                 }
7750             }
7751           int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7752           if(nbOfNodesInCell>0)
7753             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7754           else
7755             {
7756               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7757               throw INTERP_KERNEL::Exception(oss.str().c_str());
7758             }
7759         }
7760       else
7761         {
7762           std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7763           s.erase(-1);
7764           for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7765             {
7766               if(*it>=0 && *it<nbOfNodes)
7767                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7768               else
7769                 {
7770                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
7771                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7772                 }
7773             }
7774           if(!s.empty())
7775             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7776           else
7777             {
7778               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7779               throw INTERP_KERNEL::Exception(oss.str().c_str());
7780             }
7781         }
7782     }
7783   return ret.retn();
7784 }
7785
7786 /*!
7787  * Returns a new DataArrayDouble holding barycenters of specified cells. The
7788  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7789  * are specified via an array of cell ids. 
7790  *  \warning Validity of the specified cell ids is not checked! 
7791  *           Valid range is [ 0, \a this->getNumberOfCells() ).
7792  *  \param [in] begin - an array of cell ids of interest.
7793  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7794  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7795  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7796  *          caller is to delete this array using decrRef() as it is no more needed. 
7797  *  \throw If the coordinates array is not set.
7798  *  \throw If the nodal connectivity of cells is not defined.
7799  *
7800  *  \if ENABLE_EXAMPLES
7801  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7802  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7803  *  \endif
7804  */
7805 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7806 {
7807   DataArrayDouble *ret=DataArrayDouble::New();
7808   int spaceDim=getSpaceDimension();
7809   int nbOfTuple=(int)std::distance(begin,end);
7810   ret->alloc(nbOfTuple,spaceDim);
7811   double *ptToFill=ret->getPointer();
7812   double *tmp=new double[spaceDim];
7813   const int *nodal=_nodal_connec->getConstPointer();
7814   const int *nodalI=_nodal_connec_index->getConstPointer();
7815   const double *coor=_coords->getConstPointer();
7816   for(const int *w=begin;w!=end;w++)
7817     {
7818       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7819       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7820       ptToFill+=spaceDim;
7821     }
7822   delete [] tmp;
7823   return ret;
7824 }
7825
7826 /*!
7827  * 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".
7828  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7829  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7830  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7831  * This method is useful to detect 2D cells in 3D space that are not coplanar.
7832  * 
7833  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7834  * \throw If spaceDim!=3 or meshDim!=2.
7835  * \throw If connectivity of \a this is invalid.
7836  * \throw If connectivity of a cell in \a this points to an invalid node.
7837  */
7838 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7839 {
7840   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7841   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7842   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7843     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7844   ret->alloc(nbOfCells,4);
7845   double *retPtr(ret->getPointer());
7846   const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7847   const double *coor(_coords->begin());
7848   for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7849     {
7850       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7851       if(nodalI[1]-nodalI[0]>=3)
7852         {
7853           for(int j=0;j<3;j++)
7854             {
7855               int nodeId(nodal[nodalI[0]+1+j]);
7856               if(nodeId>=0 && nodeId<nbOfNodes)
7857                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7858               else
7859                 {
7860                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7861                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7862                 }
7863             }
7864         }
7865       else
7866         {
7867           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7868           throw INTERP_KERNEL::Exception(oss.str().c_str());
7869         }
7870       INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7871       retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7872     }
7873   return ret.retn();
7874 }
7875
7876 /*!
7877  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7878  * 
7879  */
7880 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7881 {
7882   if(!da)
7883     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7884   da->checkAllocated();
7885   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7886   ret->setCoords(da);
7887   int nbOfTuples=da->getNumberOfTuples();
7888   MCAuto<DataArrayInt> c=DataArrayInt::New();
7889   MCAuto<DataArrayInt> cI=DataArrayInt::New();
7890   c->alloc(2*nbOfTuples,1);
7891   cI->alloc(nbOfTuples+1,1);
7892   int *cp=c->getPointer();
7893   int *cip=cI->getPointer();
7894   *cip++=0;
7895   for(int i=0;i<nbOfTuples;i++)
7896     {
7897       *cp++=INTERP_KERNEL::NORM_POINT1;
7898       *cp++=i;
7899       *cip++=2*(i+1);
7900     }
7901   ret->setConnectivity(c,cI,true);
7902   return ret.retn();
7903 }
7904 /*!
7905  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7906  * Cells and nodes of
7907  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7908  *  \param [in] mesh1 - the first mesh.
7909  *  \param [in] mesh2 - the second mesh.
7910  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7911  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7912  *          is no more needed.
7913  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7914  *  \throw If the coordinates array is not set in none of the meshes.
7915  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7916  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7917  */
7918 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7919 {
7920   std::vector<const MEDCouplingUMesh *> tmp(2);
7921   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7922   return MergeUMeshes(tmp);
7923 }
7924
7925 /*!
7926  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7927  * Cells and nodes of
7928  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7929  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7930  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7931  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7932  *          is no more needed.
7933  *  \throw If \a a.size() == 0.
7934  *  \throw If \a a[ *i* ] == NULL.
7935  *  \throw If the coordinates array is not set in none of the meshes.
7936  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7937  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7938  */
7939 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7940 {
7941   std::size_t sz=a.size();
7942   if(sz==0)
7943     return MergeUMeshesLL(a);
7944   for(std::size_t ii=0;ii<sz;ii++)
7945     if(!a[ii])
7946       {
7947         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7948         throw INTERP_KERNEL::Exception(oss.str().c_str());
7949       }
7950   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7951   std::vector< const MEDCouplingUMesh * > aa(sz);
7952   int spaceDim=-3;
7953   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7954     {
7955       const MEDCouplingUMesh *cur=a[i];
7956       const DataArrayDouble *coo=cur->getCoords();
7957       if(coo)
7958         spaceDim=coo->getNumberOfComponents();
7959     }
7960   if(spaceDim==-3)
7961     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7962   for(std::size_t i=0;i<sz;i++)
7963     {
7964       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7965       aa[i]=bb[i];
7966     }
7967   return MergeUMeshesLL(aa);
7968 }
7969
7970 /// @cond INTERNAL
7971
7972 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
7973 {
7974   if(a.empty())
7975     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
7976   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
7977   int meshDim=(*it)->getMeshDimension();
7978   int nbOfCells=(*it)->getNumberOfCells();
7979   int meshLgth=(*it++)->getNodalConnectivityArrayLen();
7980   for(;it!=a.end();it++)
7981     {
7982       if(meshDim!=(*it)->getMeshDimension())
7983         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
7984       nbOfCells+=(*it)->getNumberOfCells();
7985       meshLgth+=(*it)->getNodalConnectivityArrayLen();
7986     }
7987   std::vector<const MEDCouplingPointSet *> aps(a.size());
7988   std::copy(a.begin(),a.end(),aps.begin());
7989   MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
7990   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
7991   ret->setCoords(pts);
7992   MCAuto<DataArrayInt> c=DataArrayInt::New();
7993   c->alloc(meshLgth,1);
7994   int *cPtr=c->getPointer();
7995   MCAuto<DataArrayInt> cI=DataArrayInt::New();
7996   cI->alloc(nbOfCells+1,1);
7997   int *cIPtr=cI->getPointer();
7998   *cIPtr++=0;
7999   int offset=0;
8000   int offset2=0;
8001   for(it=a.begin();it!=a.end();it++)
8002     {
8003       int curNbOfCell=(*it)->getNumberOfCells();
8004       const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8005       const int *curC=(*it)->_nodal_connec->getConstPointer();
8006       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8007       for(int j=0;j<curNbOfCell;j++)
8008         {
8009           const int *src=curC+curCI[j];
8010           *cPtr++=*src++;
8011           for(;src!=curC+curCI[j+1];src++,cPtr++)
8012             {
8013               if(*src!=-1)
8014                 *cPtr=*src+offset2;
8015               else
8016                 *cPtr=-1;
8017             }
8018         }
8019       offset+=curCI[curNbOfCell];
8020       offset2+=(*it)->getNumberOfNodes();
8021     }
8022   //
8023   ret->setConnectivity(c,cI,true);
8024   return ret.retn();
8025 }
8026
8027 /// @endcond
8028
8029 /*!
8030  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8031  * dimension and sharing the node coordinates array.
8032  * All cells of the first mesh precede all cells of the second mesh
8033  * within the result mesh. 
8034  *  \param [in] mesh1 - the first mesh.
8035  *  \param [in] mesh2 - the second mesh.
8036  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8037  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8038  *          is no more needed.
8039  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8040  *  \throw If the meshes do not share the node coordinates array.
8041  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8042  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8043  */
8044 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8045 {
8046   std::vector<const MEDCouplingUMesh *> tmp(2);
8047   tmp[0]=mesh1; tmp[1]=mesh2;
8048   return MergeUMeshesOnSameCoords(tmp);
8049 }
8050
8051 /*!
8052  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8053  * dimension and sharing the node coordinates array.
8054  * All cells of the *i*-th mesh precede all cells of the
8055  * (*i*+1)-th mesh within the result mesh.
8056  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8057  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8058  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8059  *          is no more needed.
8060  *  \throw If \a a.size() == 0.
8061  *  \throw If \a a[ *i* ] == NULL.
8062  *  \throw If the meshes do not share the node coordinates array.
8063  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
8064  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8065  */
8066 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8067 {
8068   if(meshes.empty())
8069     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8070   for(std::size_t ii=0;ii<meshes.size();ii++)
8071     if(!meshes[ii])
8072       {
8073         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8074         throw INTERP_KERNEL::Exception(oss.str().c_str());
8075       }
8076   const DataArrayDouble *coords=meshes.front()->getCoords();
8077   int meshDim=meshes.front()->getMeshDimension();
8078   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8079   int meshLgth=0;
8080   int meshIndexLgth=0;
8081   for(;iter!=meshes.end();iter++)
8082     {
8083       if(coords!=(*iter)->getCoords())
8084         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8085       if(meshDim!=(*iter)->getMeshDimension())
8086         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8087       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8088       meshIndexLgth+=(*iter)->getNumberOfCells();
8089     }
8090   MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8091   nodal->alloc(meshLgth,1);
8092   int *nodalPtr=nodal->getPointer();
8093   MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8094   nodalIndex->alloc(meshIndexLgth+1,1);
8095   int *nodalIndexPtr=nodalIndex->getPointer();
8096   int offset=0;
8097   for(iter=meshes.begin();iter!=meshes.end();iter++)
8098     {
8099       const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8100       const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8101       int nbOfCells=(*iter)->getNumberOfCells();
8102       int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8103       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8104       if(iter!=meshes.begin())
8105         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8106       else
8107         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8108       offset+=meshLgth2;
8109     }
8110   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8111   ret->setName("merge");
8112   ret->setMeshDimension(meshDim);
8113   ret->setConnectivity(nodal,nodalIndex,true);
8114   ret->setCoords(coords);
8115   return ret;
8116 }
8117
8118 /*!
8119  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8120  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8121  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8122  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8123  * New" mode are returned for each input mesh.
8124  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8125  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
8126  *          valid values [0,1,2], see zipConnectivityTraducer().
8127  *  \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8128  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8129  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
8130  *          no more needed.
8131  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8132  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8133  *          is no more needed.
8134  *  \throw If \a meshes.size() == 0.
8135  *  \throw If \a meshes[ *i* ] == NULL.
8136  *  \throw If the meshes do not share the node coordinates array.
8137  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8138  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
8139  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8140  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
8141  */
8142 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8143 {
8144   //All checks are delegated to MergeUMeshesOnSameCoords
8145   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8146   MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8147   corr.resize(meshes.size());
8148   std::size_t nbOfMeshes=meshes.size();
8149   int offset=0;
8150   const int *o2nPtr=o2n->getConstPointer();
8151   for(std::size_t i=0;i<nbOfMeshes;i++)
8152     {
8153       DataArrayInt *tmp=DataArrayInt::New();
8154       int curNbOfCells=meshes[i]->getNumberOfCells();
8155       tmp->alloc(curNbOfCells,1);
8156       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8157       offset+=curNbOfCells;
8158       tmp->setName(meshes[i]->getName());
8159       corr[i]=tmp;
8160     }
8161   return ret.retn();
8162 }
8163
8164 /*!
8165  * Makes all given meshes share the nodal connectivity array. The common connectivity
8166  * array is created by concatenating the connectivity arrays of all given meshes. All
8167  * the given meshes must be of the same space dimension but dimension of cells **can
8168  * differ**. This method is particulary useful in MEDLoader context to build a \ref
8169  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8170  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8171  *  \param [in,out] meshes - a vector of meshes to update.
8172  *  \throw If any of \a meshes is NULL.
8173  *  \throw If the coordinates array is not set in any of \a meshes.
8174  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8175  *  \throw If \a meshes are of different space dimension.
8176  */
8177 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8178 {
8179   std::size_t sz=meshes.size();
8180   if(sz==0 || sz==1)
8181     return;
8182   std::vector< const DataArrayDouble * > coords(meshes.size());
8183   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8184   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8185     {
8186       if((*it))
8187         {
8188           (*it)->checkConnectivityFullyDefined();
8189           const DataArrayDouble *coo=(*it)->getCoords();
8190           if(coo)
8191             *it2=coo;
8192           else
8193             {
8194               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8195               oss << " has no coordinate array defined !";
8196               throw INTERP_KERNEL::Exception(oss.str().c_str());
8197             }
8198         }
8199       else
8200         {
8201           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8202           oss << " is null !";
8203           throw INTERP_KERNEL::Exception(oss.str().c_str());
8204         }
8205     }
8206   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8207   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8208   int offset=(*it)->getNumberOfNodes();
8209   (*it++)->setCoords(res);
8210   for(;it!=meshes.end();it++)
8211     {
8212       int oldNumberOfNodes=(*it)->getNumberOfNodes();
8213       (*it)->setCoords(res);
8214       (*it)->shiftNodeNumbersInConn(offset);
8215       offset+=oldNumberOfNodes;
8216     }
8217 }
8218
8219 /*!
8220  * Merges nodes coincident with a given precision within all given meshes that share
8221  * the nodal connectivity array. The given meshes **can be of different** mesh
8222  * dimension. This method is particulary useful in MEDLoader context to build a \ref
8223  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8224  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. 
8225  *  \param [in,out] meshes - a vector of meshes to update.
8226  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8227  *  \throw If any of \a meshes is NULL.
8228  *  \throw If the \a meshes do not share the same node coordinates array.
8229  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8230  */
8231 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8232 {
8233   if(meshes.empty())
8234     return ;
8235   std::set<const DataArrayDouble *> s;
8236   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8237     {
8238       if(*it)
8239         s.insert((*it)->getCoords());
8240       else
8241         {
8242           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 !";
8243           throw INTERP_KERNEL::Exception(oss.str().c_str());
8244         }
8245     }
8246   if(s.size()!=1)
8247     {
8248       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 !";
8249       throw INTERP_KERNEL::Exception(oss.str().c_str());
8250     }
8251   const DataArrayDouble *coo=*(s.begin());
8252   if(!coo)
8253     return;
8254   //
8255   DataArrayInt *comm,*commI;
8256   coo->findCommonTuples(eps,-1,comm,commI);
8257   MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8258   int oldNbOfNodes=coo->getNumberOfTuples();
8259   int newNbOfNodes;
8260   MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8261   if(oldNbOfNodes==newNbOfNodes)
8262     return ;
8263   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8264   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8265     {
8266       (*it)->renumberNodesInConn(o2n->getConstPointer());
8267       (*it)->setCoords(newCoords);
8268     } 
8269 }
8270
8271 /*!
8272  * This method takes in input a cell defined by its MEDcouplingUMesh connectivity [ \a connBg , \a connEnd ) and returns its extruded cell by inserting the result at the end of ret.
8273  * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8274  * \param isQuad specifies the policy of connectivity.
8275  * @ret in/out parameter in which the result will be append
8276  */
8277 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8278 {
8279   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8280   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8281   ret.push_back(cm.getExtrudedType());
8282   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8283   switch(flatType)
8284   {
8285     case INTERP_KERNEL::NORM_POINT1:
8286       {
8287         ret.push_back(connBg[1]);
8288         ret.push_back(connBg[1]+nbOfNodesPerLev);
8289         break;
8290       }
8291     case INTERP_KERNEL::NORM_SEG2:
8292       {
8293         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8294         ret.insert(ret.end(),conn,conn+4);
8295         break;
8296       }
8297     case INTERP_KERNEL::NORM_SEG3:
8298       {
8299         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8300         ret.insert(ret.end(),conn,conn+8);
8301         break;
8302       }
8303     case INTERP_KERNEL::NORM_QUAD4:
8304       {
8305         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8306         ret.insert(ret.end(),conn,conn+8);
8307         break;
8308       }
8309     case INTERP_KERNEL::NORM_TRI3:
8310       {
8311         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8312         ret.insert(ret.end(),conn,conn+6);
8313         break;
8314       }
8315     case INTERP_KERNEL::NORM_TRI6:
8316       {
8317         int conn[15]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4],connBg[5],connBg[6],connBg[4]+deltaz,connBg[5]+deltaz,connBg[6]+deltaz,
8318           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8319         ret.insert(ret.end(),conn,conn+15);
8320         break;
8321       }
8322     case INTERP_KERNEL::NORM_QUAD8:
8323       {
8324         int conn[20]={
8325           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8326           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8327           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8328         };
8329         ret.insert(ret.end(),conn,conn+20);
8330         break;
8331       }
8332     case INTERP_KERNEL::NORM_POLYGON:
8333       {
8334         std::back_insert_iterator< std::vector<int> > ii(ret);
8335         std::copy(connBg+1,connEnd,ii);
8336         *ii++=-1;
8337         std::reverse_iterator<const int *> rConnBg(connEnd);
8338         std::reverse_iterator<const int *> rConnEnd(connBg+1);
8339         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8340         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8341         for(std::size_t i=0;i<nbOfRadFaces;i++)
8342           {
8343             *ii++=-1;
8344             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8345             std::copy(conn,conn+4,ii);
8346           }
8347         break;
8348       }
8349     default:
8350       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8351   }
8352 }
8353
8354 /*!
8355  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8356  */
8357 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8358 {
8359   std::size_t i, ip1;
8360   double v[3]={0.,0.,0.};
8361   std::size_t sz=std::distance(begin,end);
8362   if(isQuadratic)
8363     sz/=2;
8364   for(i=0;i<sz;i++)
8365     {
8366       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];
8367       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8368       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8369     }
8370   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8371
8372   // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8373   // SEG3 forming a circle):
8374   if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8375     {
8376       v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8377       for(std::size_t j=0;j<sz;j++)
8378         {
8379           if (j%2)  // current point i is quadratic, next point i+1 is standard
8380             {
8381               i = sz+j;
8382               ip1 = (j+1)%sz; // ip1 = "i+1"
8383             }
8384           else      // current point i is standard, next point i+1 is quadratic
8385             {
8386               i = j;
8387               ip1 = j+sz;
8388             }
8389           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8390           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8391           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8392         }
8393       ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8394     }
8395   return (ret>0.);
8396 }
8397
8398 /*!
8399  * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8400  */
8401 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8402 {
8403   std::vector<std::pair<int,int> > edges;
8404   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8405   const int *bgFace=begin;
8406   for(std::size_t i=0;i<nbOfFaces;i++)
8407     {
8408       const int *endFace=std::find(bgFace+1,end,-1);
8409       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8410       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8411         {
8412           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8413           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8414             return false;
8415           edges.push_back(p1);
8416         }
8417       bgFace=endFace+1;
8418     }
8419   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8420 }
8421
8422 /*!
8423  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8424  */
8425 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8426 {
8427   double vec0[3],vec1[3];
8428   std::size_t sz=std::distance(begin,end);
8429   if(sz%2!=0)
8430     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8431   int nbOfNodes=(int)sz/2;
8432   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8433   const double *pt0=coords+3*begin[0];
8434   const double *pt1=coords+3*begin[nbOfNodes];
8435   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8436   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8437 }
8438
8439 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8440 {
8441   std::size_t sz=std::distance(begin,end);
8442   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8443   std::size_t nbOfNodes(sz/2);
8444   std::copy(begin,end,(int *)tmp);
8445   for(std::size_t j=1;j<nbOfNodes;j++)
8446     {
8447       begin[j]=tmp[nbOfNodes-j];
8448       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8449     }
8450 }
8451
8452 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8453 {
8454   std::size_t sz=std::distance(begin,end);
8455   if(sz!=4)
8456     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8457   double vec0[3],vec1[3];
8458   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8459   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]; 
8460   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;
8461 }
8462
8463 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8464 {
8465   std::size_t sz=std::distance(begin,end);
8466   if(sz!=5)
8467     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8468   double vec0[3];
8469   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8470   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8471   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8472 }
8473
8474 /*!
8475  * 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 ) 
8476  * 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
8477  * a 2D space.
8478  *
8479  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8480  * \param [in] coords the coordinates with nb of components exactly equal to 3
8481  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8482  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8483  * \param [out] res the result is put at the end of the vector without any alteration of the data.
8484  */
8485 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8486 {
8487   int nbFaces=std::count(begin+1,end,-1)+1;
8488   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8489   double *vPtr=v->getPointer();
8490   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8491   double *pPtr=p->getPointer();
8492   const int *stFaceConn=begin+1;
8493   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8494     {
8495       const int *endFaceConn=std::find(stFaceConn,end,-1);
8496       ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8497       stFaceConn=endFaceConn+1;
8498     }
8499   pPtr=p->getPointer(); vPtr=v->getPointer();
8500   DataArrayInt *comm1=0,*commI1=0;
8501   v->findCommonTuples(eps,-1,comm1,commI1);
8502   MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8503   const int *comm1Ptr=comm1->getConstPointer();
8504   const int *commI1Ptr=commI1->getConstPointer();
8505   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8506   res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8507   //
8508   MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8509   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8510   mm->finishInsertingCells();
8511   //
8512   for(int i=0;i<nbOfGrps1;i++)
8513     {
8514       int vecId=comm1Ptr[commI1Ptr[i]];
8515       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8516       DataArrayInt *comm2=0,*commI2=0;
8517       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8518       MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8519       const int *comm2Ptr=comm2->getConstPointer();
8520       const int *commI2Ptr=commI2->getConstPointer();
8521       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8522       for(int j=0;j<nbOfGrps2;j++)
8523         {
8524           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8525             {
8526               res->insertAtTheEnd(begin,end);
8527               res->pushBackSilent(-1);
8528             }
8529           else
8530             {
8531               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8532               MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8533               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8534               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8535               MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8536               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8537               MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8538               MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8539               const int *idsNodePtr=idsNode->getConstPointer();
8540               double center[3]; center[0]=pPtr[pointId]*vPtr[3*vecId]; center[1]=pPtr[pointId]*vPtr[3*vecId+1]; center[2]=pPtr[pointId]*vPtr[3*vecId+2];
8541               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8542               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8543               if(std::abs(norm)>eps)
8544                 {
8545                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8546                   mm3->rotate(center,vec,angle);
8547                 }
8548               mm3->changeSpaceDimension(2);
8549               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8550               const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8551               const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8552               int nbOfCells=mm4->getNumberOfCells();
8553               for(int k=0;k<nbOfCells;k++)
8554                 {
8555                   int l=0;
8556                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8557                     res->pushBackSilent(idsNodePtr[*work]);
8558                   res->pushBackSilent(-1);
8559                 }
8560             }
8561         }
8562     }
8563   res->popBackSilent();
8564 }
8565
8566 /*!
8567  * 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
8568  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8569  * 
8570  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8571  * \param [in] coords coordinates expected to have 3 components.
8572  * \param [in] begin start of the nodal connectivity of the face.
8573  * \param [in] end end of the nodal connectivity (excluded) of the face.
8574  * \param [out] v the normalized vector of size 3
8575  * \param [out] p the pos of plane
8576  */
8577 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8578 {
8579   std::size_t nbPoints=std::distance(begin,end);
8580   if(nbPoints<3)
8581     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8582   double vec[3]={0.,0.,0.};
8583   std::size_t j=0;
8584   bool refFound=false;
8585   for(;j<nbPoints-1 && !refFound;j++)
8586     {
8587       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8588       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8589       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8590       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8591       if(norm>eps)
8592         {
8593           refFound=true;
8594           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8595         }
8596     }
8597   for(std::size_t i=j;i<nbPoints-1;i++)
8598     {
8599       double curVec[3];
8600       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8601       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8602       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8603       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8604       if(norm<eps)
8605         continue;
8606       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8607       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];
8608       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8609       if(norm>eps)
8610         {
8611           v[0]/=norm; v[1]/=norm; v[2]/=norm;
8612           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8613           return ;
8614         }
8615     }
8616   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8617 }
8618
8619 /*!
8620  * This method tries to obtain a well oriented polyhedron.
8621  * If the algorithm fails, an exception will be thrown.
8622  */
8623 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8624 {
8625   std::list< std::pair<int,int> > edgesOK,edgesFinished;
8626   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8627   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8628   isPerm[0]=true;
8629   int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8630   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8631   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8632   //
8633   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8634     {
8635       bgFace=begin;
8636       std::size_t smthChanged=0;
8637       for(std::size_t i=0;i<nbOfFaces;i++)
8638         {
8639           endFace=std::find(bgFace+1,end,-1);
8640           nbOfEdgesInFace=std::distance(bgFace,endFace);
8641           if(!isPerm[i])
8642             {
8643               bool b;
8644               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8645                 {
8646                   std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8647                   std::pair<int,int> p2(p1.second,p1.first);
8648                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8649                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8650                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8651                 }
8652               if(isPerm[i])
8653                 { 
8654                   if(!b)
8655                     std::reverse(bgFace+1,endFace);
8656                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8657                     {
8658                       std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8659                       std::pair<int,int> p2(p1.second,p1.first);
8660                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8661                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8662                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8663                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8664                       std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8665                       if(it!=edgesOK.end())
8666                         {
8667                           edgesOK.erase(it);
8668                           edgesFinished.push_back(p1);
8669                         }
8670                       else
8671                         edgesOK.push_back(p1);
8672                     }
8673                 }
8674             }
8675           bgFace=endFace+1;
8676         }
8677       if(smthChanged==0)
8678         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8679     }
8680   if(!edgesOK.empty())
8681     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8682   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8683     {//not lucky ! The first face was not correctly oriented : reorient all faces...
8684       bgFace=begin;
8685       for(std::size_t i=0;i<nbOfFaces;i++)
8686         {
8687           endFace=std::find(bgFace+1,end,-1);
8688           std::reverse(bgFace+1,endFace);
8689           bgFace=endFace+1;
8690         }
8691     }
8692 }
8693
8694 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8695 {
8696   int nbOfNodesExpected(skin->getNumberOfNodes());
8697   const int *n2oPtr(n2o->getConstPointer());
8698   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8699   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8700   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8701   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8702   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8703   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8704   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_POLYGON;
8705   if(nbOfNodesExpected<1)
8706     return ret.retn();
8707   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8708   *work++=n2oPtr[prevNode];
8709   for(int i=1;i<nbOfNodesExpected;i++)
8710     {
8711       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8712         {
8713           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8714           conn.erase(prevNode);
8715           if(conn.size()==1)
8716             {
8717               int curNode(*(conn.begin()));
8718               *work++=n2oPtr[curNode];
8719               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8720               shar.erase(prevCell);
8721               if(shar.size()==1)
8722                 {
8723                   prevCell=*(shar.begin());
8724                   prevNode=curNode;
8725                 }
8726               else
8727                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8728             }
8729           else
8730             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8731         }
8732       else
8733         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8734     }
8735   return ret.retn();
8736 }
8737
8738 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8739 {
8740   int nbOfNodesExpected(skin->getNumberOfNodes());
8741   int nbOfTurn(nbOfNodesExpected/2);
8742   const int *n2oPtr(n2o->getConstPointer());
8743   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8744   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8745   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8746   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8747   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8748   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8749   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_QPOLYG;
8750   if(nbOfNodesExpected<1)
8751     return ret.retn();
8752   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8753   *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8754   for(int i=1;i<nbOfTurn;i++)
8755     {
8756       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8757         {
8758           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8759           conn.erase(prevNode);
8760           if(conn.size()==1)
8761             {
8762               int curNode(*(conn.begin()));
8763               *work=n2oPtr[curNode];
8764               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8765               shar.erase(prevCell);
8766               if(shar.size()==1)
8767                 {
8768                   int curCell(*(shar.begin()));
8769                   work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8770                   prevCell=curCell;
8771                   prevNode=curNode;
8772                   work++;
8773                 }
8774               else
8775                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8776             }
8777           else
8778             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8779         }
8780       else
8781         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8782     }
8783   return ret.retn();
8784 }
8785
8786 /*!
8787  * This method makes the assumption spacedimension == meshdimension == 2.
8788  * This method works only for linear cells.
8789  * 
8790  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8791  */
8792 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8793 {
8794   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8795     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8796   MCAuto<MEDCouplingUMesh> skin(computeSkin());
8797   int oldNbOfNodes(skin->getNumberOfNodes());
8798   MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8799   int nbOfNodesExpected(skin->getNumberOfNodes());
8800   MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8801   int nbCells(skin->getNumberOfCells());
8802   if(nbCells==nbOfNodesExpected)
8803     return buildUnionOf2DMeshLinear(skin,n2o);
8804   else if(2*nbCells==nbOfNodesExpected)
8805     return buildUnionOf2DMeshQuadratic(skin,n2o);
8806   else
8807     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8808 }
8809
8810 /*!
8811  * This method makes the assumption spacedimension == meshdimension == 3.
8812  * This method works only for linear cells.
8813  * 
8814  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8815  */
8816 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8817 {
8818   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8819     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8820   MCAuto<MEDCouplingUMesh> m=computeSkin();
8821   const int *conn=m->getNodalConnectivity()->getConstPointer();
8822   const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8823   int nbOfCells=m->getNumberOfCells();
8824   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8825   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
8826   if(nbOfCells<1)
8827     return ret.retn();
8828   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8829   for(int i=1;i<nbOfCells;i++)
8830     {
8831       *work++=-1;
8832       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8833     }
8834   return ret.retn();
8835 }
8836
8837 /*!
8838  * \brief Creates a graph of cell neighbors
8839  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8840  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
8841  *  For example
8842  *  - index:  0 3 5 6 6
8843  *  - value:  1 2 3 2 3 3
8844  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8845  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8846  */
8847 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8848 {
8849   checkConnectivityFullyDefined();
8850
8851   int meshDim = this->getMeshDimension();
8852   MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8853   MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8854   this->getReverseNodalConnectivity(revConn,indexr);
8855   const int* indexr_ptr=indexr->getConstPointer();
8856   const int* revConn_ptr=revConn->getConstPointer();
8857
8858   const MEDCoupling::DataArrayInt* index;
8859   const MEDCoupling::DataArrayInt* conn;
8860   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8861   index=this->getNodalConnectivityIndex();
8862   int nbCells=this->getNumberOfCells();
8863   const int* index_ptr=index->getConstPointer();
8864   const int* conn_ptr=conn->getConstPointer();
8865
8866   //creating graph arcs (cell to cell relations)
8867   //arcs are stored in terms of (index,value) notation
8868   // 0 3 5 6 6
8869   // 1 2 3 2 3 3
8870   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8871   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8872
8873   //warning here one node have less than or equal effective number of cell with it
8874   //but cell could have more than effective nodes
8875   //because other equals nodes in other domain (with other global inode)
8876   std::vector <int> cell2cell_index(nbCells+1,0);
8877   std::vector <int> cell2cell;
8878   cell2cell.reserve(3*nbCells);
8879
8880   for (int icell=0; icell<nbCells;icell++)
8881     {
8882       std::map<int,int > counter;
8883       for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8884         {
8885           int inode=conn_ptr[iconn];
8886           for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8887             {
8888               int icell2=revConn_ptr[iconnr];
8889               std::map<int,int>::iterator iter=counter.find(icell2);
8890               if (iter!=counter.end()) (iter->second)++;
8891               else counter.insert(std::make_pair(icell2,1));
8892             }
8893         }
8894       for (std::map<int,int>::const_iterator iter=counter.begin();
8895            iter!=counter.end(); iter++)
8896         if (iter->second >= meshDim)
8897           {
8898             cell2cell_index[icell+1]++;
8899             cell2cell.push_back(iter->first);
8900           }
8901     }
8902   indexr->decrRef();
8903   revConn->decrRef();
8904   cell2cell_index[0]=0;
8905   for (int icell=0; icell<nbCells;icell++)
8906     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8907
8908   //filling up index and value to create skylinearray structure
8909   MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8910   return array;
8911 }
8912
8913 /*!
8914  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8915  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8916  */
8917 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8918 {
8919   double *w=zipFrmt;
8920   if(spaceDim==3)
8921     for(int i=0;i<nbOfNodesInCell;i++)
8922       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8923   else if(spaceDim==2)
8924     {
8925       for(int i=0;i<nbOfNodesInCell;i++)
8926         {
8927           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8928           *w++=0.;
8929         }
8930     }
8931   else
8932     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8933 }
8934
8935 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8936 {
8937   int nbOfCells=getNumberOfCells();
8938   if(nbOfCells<=0)
8939     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8940   static const int PARAMEDMEM2VTKTYPETRADUCER[INTERP_KERNEL::NORM_MAXTYPE+1]={1,3,21,5,9,7,22,34,23,28,-1,-1,-1,-1,10,14,13,-1,12,-1,24,-1,16,27,-1,26,-1,29,-1,-1,25,42,36,4};
8941   ofs << "  <" << getVTKDataSetType() << ">\n";
8942   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8943   ofs << "      <PointData>\n" << pointData << std::endl;
8944   ofs << "      </PointData>\n";
8945   ofs << "      <CellData>\n" << cellData << std::endl;
8946   ofs << "      </CellData>\n";
8947   ofs << "      <Points>\n";
8948   if(getSpaceDimension()==3)
8949     _coords->writeVTK(ofs,8,"Points",byteData);
8950   else
8951     {
8952       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8953       coo->writeVTK(ofs,8,"Points",byteData);
8954     }
8955   ofs << "      </Points>\n";
8956   ofs << "      <Cells>\n";
8957   const int *cPtr=_nodal_connec->getConstPointer();
8958   const int *cIPtr=_nodal_connec_index->getConstPointer();
8959   MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8960   MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8961   MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8962   MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8963   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8964   int szFaceOffsets=0,szConn=0;
8965   for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8966     {
8967       *w2=cPtr[cIPtr[i]];
8968       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8969         {
8970           *w1=-1;
8971           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8972           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8973         }
8974       else
8975         {
8976           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
8977           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
8978           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
8979           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
8980           w4=std::copy(c.begin(),c.end(),w4);
8981         }
8982     }
8983   types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
8984   types->writeVTK(ofs,8,"UInt8","types",byteData);
8985   offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
8986   if(szFaceOffsets!=0)
8987     {//presence of Polyhedra
8988       connectivity->reAlloc(szConn);
8989       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
8990       MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
8991       w1=faces->getPointer();
8992       for(int i=0;i<nbOfCells;i++)
8993         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
8994           {
8995             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
8996             *w1++=nbFaces;
8997             const int *w6=cPtr+cIPtr[i]+1,*w5=0;
8998             for(int j=0;j<nbFaces;j++)
8999               {
9000                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
9001                 *w1++=(int)std::distance(w6,w5);
9002                 w1=std::copy(w6,w5,w1);
9003                 w6=w5+1;
9004               }
9005           }
9006       faces->writeVTK(ofs,8,"Int32","faces",byteData);
9007     }
9008   connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9009   ofs << "      </Cells>\n";
9010   ofs << "    </Piece>\n";
9011   ofs << "  </" << getVTKDataSetType() << ">\n";
9012 }
9013
9014 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9015 {
9016   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9017   if(_mesh_dim==-2)
9018     { stream << " Not set !"; return ; }
9019   stream << " Mesh dimension : " << _mesh_dim << ".";
9020   if(_mesh_dim==-1)
9021     return ;
9022   if(!_coords)
9023     { stream << " No coordinates set !"; return ; }
9024   if(!_coords->isAllocated())
9025     { stream << " Coordinates set but not allocated !"; return ; }
9026   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9027   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9028   if(!_nodal_connec_index)
9029     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9030   if(!_nodal_connec_index->isAllocated())
9031     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9032   int lgth=_nodal_connec_index->getNumberOfTuples();
9033   int cpt=_nodal_connec_index->getNumberOfComponents();
9034   if(cpt!=1 || lgth<1)
9035     return ;
9036   stream << std::endl << "Number of cells : " << lgth-1 << ".";
9037 }
9038
9039 std::string MEDCouplingUMesh::getVTKDataSetType() const
9040 {
9041   return std::string("UnstructuredGrid");
9042 }
9043
9044 std::string MEDCouplingUMesh::getVTKFileExtension() const
9045 {
9046   return std::string("vtu");
9047 }
9048
9049 /*!
9050  * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9051  * returns a result mesh constituted by polygons.
9052  * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9053  * all nodes from m2.
9054  * The meshes should be in 2D space. In
9055  * addition, returns two arrays mapping cells of the result mesh to cells of the input
9056  * meshes.
9057  *  \param [in] m1 - the first input mesh which is a partitioned object. The mesh must be so that each point in the space covered by \a m1
9058  *                      must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9059  *  \param [in] m2 - the second input mesh which is a partition tool. The mesh must be so that each point in the space covered by \a m2
9060  *                      must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9061  *  \param [in] eps - precision used to detect coincident mesh entities.
9062  *  \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9063  *         cell an id of the cell of \a m1 it comes from. The caller is to delete
9064  *         this array using decrRef() as it is no more needed.
9065  *  \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9066  *         cell an id of the cell of \a m2 it comes from. -1 value means that a
9067  *         result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9068  *         any cell of \a m2. The caller is to delete this array using decrRef() as
9069  *         it is no more needed.  
9070  *  \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9071  *         MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9072  *         is no more needed.  
9073  *  \throw If the coordinates array is not set in any of the meshes.
9074  *  \throw If the nodal connectivity of cells is not defined in any of the meshes.
9075  *  \throw If any of the meshes is not a 2D mesh in 2D space.
9076  *
9077  *  \sa conformize2D, mergeNodes
9078  */
9079 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9080                                                       double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9081 {
9082   if(!m1 || !m2)
9083     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9084   m1->checkFullyDefined();
9085   m2->checkFullyDefined();
9086   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9087     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
9088
9089   // Step 1: compute all edge intersections (new nodes)
9090   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9091   MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9092   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9093   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9094   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9095                               m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9096                               addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9097   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9098   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9099   MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9100
9101   // Step 2: re-order newly created nodes according to the ordering found in m2
9102   std::vector< std::vector<int> > intersectEdge2;
9103   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9104   subDiv2.clear(); dd5=0; dd6=0;
9105
9106   // Step 3:
9107   std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9108   std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9109   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9110                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9111
9112   // Step 4: Prepare final result:
9113   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9114   addCooDa->alloc((int)(addCoo.size())/2,2);
9115   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9116   MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9117   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9118   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9119   std::vector<const DataArrayDouble *> coordss(4);
9120   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9121   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9122   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9123   MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9124   MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9125   MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9126   MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9127   ret->setConnectivity(conn,connI,true);
9128   ret->setCoords(coo);
9129   cellNb1=c1.retn(); cellNb2=c2.retn();
9130   return ret.retn();
9131 }
9132
9133 /// @cond INTERNAL
9134
9135 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9136 {
9137   if(candidates.empty())
9138     return false;
9139   for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9140     {
9141       const std::vector<int>& pool(intersectEdge1[*it]);
9142       int tmp[2]; tmp[0]=start; tmp[1]=stop;
9143       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9144         {
9145           retVal=*it+1;
9146           return true;
9147         }
9148       tmp[0]=stop; tmp[1]=start;
9149       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9150         {
9151           retVal=-*it-1;
9152           return true;
9153         }
9154     }
9155   return false;
9156 }
9157
9158 MEDCouplingUMesh *BuildMesh1DCutFrom(const MEDCouplingUMesh *mesh1D, const std::vector< std::vector<int> >& intersectEdge2, const DataArrayDouble *coords1, const std::vector<double>& addCoo, const std::map<int,int>& mergedNodes, const std::vector< std::vector<int> >& colinear2, const std::vector< std::vector<int> >& intersectEdge1,
9159                                      MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9160 {
9161   idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9162   idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9163   int nCells(mesh1D->getNumberOfCells());
9164   if(nCells!=(int)intersectEdge2.size())
9165     throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9166   const DataArrayDouble *coo2(mesh1D->getCoords());
9167   const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9168   const double *coo2Ptr(coo2->begin());
9169   int offset1(coords1->getNumberOfTuples());
9170   int offset2(offset1+coo2->getNumberOfTuples());
9171   int offset3(offset2+addCoo.size()/2);
9172   std::vector<double> addCooQuad;
9173   MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9174   int tmp[4],cicnt(0),kk(0);
9175   for(int i=0;i<nCells;i++)
9176     {
9177       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9178       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9179       const std::vector<int>& subEdges(intersectEdge2[i]);
9180       int nbSubEdge(subEdges.size()/2);
9181       for(int j=0;j<nbSubEdge;j++,kk++)
9182         {
9183           MCAuto<INTERP_KERNEL::Node> n1(MEDCouplingUMeshBuildQPNode(subEdges[2*j],coords1->begin(),offset1,coo2Ptr,offset2,addCoo)),n2(MEDCouplingUMeshBuildQPNode(subEdges[2*j+1],coords1->begin(),offset1,coo2Ptr,offset2,addCoo));
9184           MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9185           INTERP_KERNEL::Edge *e2Ptr(e2);
9186           std::map<int,int>::const_iterator itm;
9187           if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9188             {
9189               tmp[0]=INTERP_KERNEL::NORM_SEG3;
9190               itm=mergedNodes.find(subEdges[2*j]);
9191               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9192               itm=mergedNodes.find(subEdges[2*j+1]);
9193               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9194               tmp[3]=offset3+(int)addCooQuad.size()/2;
9195               double tmp2[2];
9196               e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9197               cicnt+=4;
9198               cOut->insertAtTheEnd(tmp,tmp+4);
9199               ciOut->pushBackSilent(cicnt);
9200             }
9201           else
9202             {
9203               tmp[0]=INTERP_KERNEL::NORM_SEG2;
9204               itm=mergedNodes.find(subEdges[2*j]);
9205               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9206               itm=mergedNodes.find(subEdges[2*j+1]);
9207               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9208               cicnt+=3;
9209               cOut->insertAtTheEnd(tmp,tmp+3);
9210               ciOut->pushBackSilent(cicnt);
9211             }
9212           int tmp00;
9213           if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9214             {
9215               idsInRetColinear->pushBackSilent(kk);
9216               idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9217             }
9218         }
9219       e->decrRef();
9220     }
9221   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9222   ret->setConnectivity(cOut,ciOut,true);
9223   MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9224   arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9225   MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9226   std::vector<const DataArrayDouble *> coordss(4);
9227   coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9228   MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9229   ret->setCoords(arr);
9230   return ret.retn();
9231 }
9232
9233 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9234 {
9235   std::vector<int> allEdges;
9236   for(const int *it2(descBg);it2!=descEnd;it2++)
9237     {
9238       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9239       if(*it2>0)
9240         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9241       else
9242         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9243     }
9244   std::size_t nb(allEdges.size());
9245   if(nb%2!=0)
9246     throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9247   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9248   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9249   ret->setCoords(coords);
9250   ret->allocateCells(1);
9251   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9252   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9253     connOut[kk]=allEdges[2*kk];
9254   ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9255   return ret.retn();
9256 }
9257
9258 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9259 {
9260   const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9261   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9262   std::size_t ii(0);
9263   unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9264   if(sz!=std::distance(descBg,descEnd))
9265     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9266   INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9267   std::vector<int> allEdges,centers;
9268   const double *coordsPtr(coords->begin());
9269   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9270   int offset(coords->getNumberOfTuples());
9271   for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9272     {
9273       INTERP_KERNEL::NormalizedCellType typeOfSon;
9274       cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9275       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9276       if(*it2>0)
9277         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9278       else
9279         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9280       if(edge1.size()==2)
9281         centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9282       else
9283         {//the current edge has been subsplit -> create corresponding centers.
9284           std::size_t nbOfCentersToAppend(edge1.size()/2);
9285           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9286           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9287           std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9288           for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9289             {
9290               double tmpp[2];
9291               const double *aa(coordsPtr+2*(*it3++));
9292               const double *bb(coordsPtr+2*(*it3++));
9293               ee->getMiddleOfPoints(aa,bb,tmpp);
9294               addCoo->insertAtTheEnd(tmpp,tmpp+2);
9295               centers.push_back(offset+k);
9296             }
9297         }
9298     }
9299   std::size_t nb(allEdges.size());
9300   if(nb%2!=0)
9301     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9302   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9303   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9304   if(addCoo->empty())
9305     ret->setCoords(coords);
9306   else
9307     {
9308       addCoo->rearrange(2);
9309       addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9310       ret->setCoords(addCoo);
9311     }
9312   ret->allocateCells(1);
9313   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9314   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9315     connOut[kk]=allEdges[2*kk];
9316   connOut.insert(connOut.end(),centers.begin(),centers.end());
9317   ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9318   return ret.retn();
9319 }
9320
9321 /*!
9322  * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9323  * of those edges.
9324  *
9325  * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9326  */
9327 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9328 {
9329   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9330   if(!cm.isQuadratic())
9331     return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9332   else
9333     return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9334 }
9335
9336 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9337 {
9338   bool isQuad(false);
9339   for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9340     {
9341       const INTERP_KERNEL::Edge *ee(*it);
9342       if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9343         isQuad=true;
9344     }
9345   if(!isQuad)
9346     mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9347   else
9348     {
9349       const double *coo(mesh2D->getCoords()->begin());
9350       std::size_t sz(conn.size());
9351       std::vector<double> addCoo;
9352       std::vector<int> conn2(conn);
9353       int offset(mesh2D->getNumberOfNodes());
9354       for(std::size_t i=0;i<sz;i++)
9355         {
9356           double tmp[2];
9357           edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9358           addCoo.insert(addCoo.end(),tmp,tmp+2);
9359           conn2.push_back(offset+(int)i);
9360         }
9361       mesh2D->getCoords()->rearrange(1);
9362       mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9363       mesh2D->getCoords()->rearrange(2);
9364       mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9365     }
9366 }
9367
9368 /*!
9369  * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9370  *
9371  * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9372  * a set of edges defined in \a splitMesh1D.
9373  */
9374 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9375                              std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9376 {
9377   std::size_t nb(edge1Bis.size()/2);
9378   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9379   int iEnd(splitMesh1D->getNumberOfCells());
9380   if(iEnd==0)
9381     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9382   std::size_t ii,jj;
9383   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9384   for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9385   for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9386   //
9387   if(jj==nb)
9388     {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9389       out0.resize(1); out1.resize(1);
9390       std::vector<int>& connOut(out0[0]);
9391       connOut.resize(nbOfEdgesOf2DCellSplit);
9392       std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9393       edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9394       for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9395         {
9396           connOut[kk]=edge1Bis[2*kk];
9397           edgesPtr[kk]=edge1BisPtr[2*kk];
9398         }
9399     }
9400   else
9401     {
9402       // [i,iEnd[ contains the
9403       out0.resize(2); out1.resize(2);
9404       std::vector<int>& connOutLeft(out0[0]);
9405       std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9406       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9407       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9408       for(std::size_t k=ii;k<jj+1;k++)
9409         { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9410       std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9411       for(int ik=0;ik<iEnd;ik++)
9412         {
9413           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9414           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9415           ees[ik]=ee;
9416         }
9417       for(int ik=iEnd-1;ik>=0;ik--)
9418         connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9419       for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9420         { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9421       eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9422       for(int ik=0;ik<iEnd;ik++)
9423         connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9424       eright.insert(eright.end(),ees.begin(),ees.end());
9425     }
9426 }
9427
9428 /// @endcond
9429
9430 /// @cond INTERNAL
9431
9432 struct CellInfo
9433 {
9434 public:
9435   CellInfo() { }
9436   CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9437 public:
9438   std::vector<int> _edges;
9439   std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9440 };
9441
9442 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9443 {
9444   std::size_t nbe(edges.size());
9445   std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9446   for(std::size_t i=0;i<nbe;i++)
9447     {
9448       edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9449       edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9450     }
9451   _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9452   std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9453   std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9454 }
9455
9456 class EdgeInfo
9457 {
9458 public:
9459   EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9460   EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9461   bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9462   void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9463   void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9464 private:
9465   int _istart;
9466   int _iend;
9467   MCAuto<MEDCouplingUMesh> _mesh;
9468   MCAuto<INTERP_KERNEL::Edge> _edge;
9469   int _left;
9470   int _right;
9471 };
9472
9473 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9474 {
9475   const MEDCouplingUMesh *mesh(_mesh);
9476   if(mesh)
9477     return ;
9478   if(_right<pos)
9479     return ;
9480   if(_left>pos)
9481     { _left++; _right++; return ; }
9482   if(_right==pos)
9483     {
9484       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9485       if((isLeft && isRight) || (!isLeft && !isRight))
9486         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9487       if(isLeft)
9488         return ;
9489       if(isRight)
9490         {
9491           _right++;
9492           return ;
9493         }
9494     }
9495   if(_left==pos)
9496     {
9497       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9498       if((isLeft && isRight) || (!isLeft && !isRight))
9499         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9500       if(isLeft)
9501         {
9502           _right++;
9503           return ;
9504         }
9505       if(isRight)
9506         {
9507           _left++;
9508           _right++;
9509           return ;
9510         }
9511     }
9512 }
9513
9514 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9515 {
9516   const MEDCouplingUMesh *mesh(_mesh);
9517   if(!mesh)
9518     {
9519       neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9520     }
9521   else
9522     {// not fully splitting cell case
9523       if(mesh2D->getNumberOfCells()==1)
9524         {//little optimization. 1 cell no need to find in which cell mesh is !
9525           neighbors[0]=offset; neighbors[1]=offset;
9526           return;
9527         }
9528       else
9529         {
9530           MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9531           int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9532           if(cellId==-1)
9533             throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9534           neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9535         }
9536     }
9537 }
9538
9539 class VectorOfCellInfo
9540 {
9541 public:
9542   VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9543   std::size_t size() const { return _pool.size(); }
9544   int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9545   void setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs);
9546   const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9547   const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9548   MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9549   void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9550 private:
9551   int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9552   void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9553   const CellInfo& get(int pos) const;
9554   CellInfo& get(int pos);
9555 private:
9556   std::vector<CellInfo> _pool;
9557   MCAuto<MEDCouplingUMesh> _ze_mesh;
9558   std::vector<EdgeInfo> _edge_info;
9559 };
9560
9561 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9562 {
9563   _pool[0]._edges=edges;
9564   _pool[0]._edges_ptr=edgesPtr;
9565 }
9566
9567 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9568 {
9569   if(_pool.empty())
9570     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9571   if(_pool.size()==1)
9572     return 0;
9573   const MEDCouplingUMesh *zeMesh(_ze_mesh);
9574   if(!zeMesh)
9575     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9576   MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9577   return zeMesh->getCellContainingPoint(barys->begin(),eps);
9578 }
9579
9580 void VectorOfCellInfo::setMeshAt(int pos, const MCAuto<MEDCouplingUMesh>& mesh, int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh1DInCase, const std::vector< std::vector<int> >& edges, const std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& edgePtrs)
9581 {
9582   get(pos);//to check pos
9583   bool isFast(pos==0 && _pool.size()==1);
9584   std::size_t sz(edges.size());
9585   // dealing with edges
9586   if(sz==1)
9587     _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9588   else
9589     _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9590   //
9591   std::vector<CellInfo> pool(_pool.size()-1+sz);
9592   for(int i=0;i<pos;i++)
9593     pool[i]=_pool[i];
9594   for(std::size_t j=0;j<sz;j++)
9595     pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9596   for(int i=pos+1;i<(int)_pool.size();i++)
9597     pool[i+sz-1]=_pool[i];
9598   _pool=pool;
9599   //
9600   if(sz==2)
9601     updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9602   //
9603   if(isFast)
9604     {
9605       _ze_mesh=mesh;
9606       return ;
9607     }
9608   //
9609   std::vector< MCAuto<MEDCouplingUMesh> > ms;
9610   if(pos>0)
9611     {
9612       MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9613       ms.push_back(elt);
9614     }
9615   ms.push_back(mesh);
9616   if(pos<_ze_mesh->getNumberOfCells()-1)
9617   {
9618     MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9619     ms.push_back(elt);
9620   }
9621   std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9622   for(std::size_t j=0;j<ms2.size();j++)
9623     ms2[j]=ms[j];
9624   _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9625 }
9626
9627 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9628 {
9629   _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9630 }
9631
9632 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9633 {
9634   if(pos<0)
9635     throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9636   int ret(0);
9637   for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9638     {
9639       if((*it).isInMyRange(pos))
9640         return ret;
9641     }
9642   throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9643 }
9644
9645 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9646 {
9647   get(pos);//to check;
9648   if(_edge_info.empty())
9649     return ;
9650   std::size_t sz(_edge_info.size()-1);
9651   for(std::size_t i=0;i<sz;i++)
9652     _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9653 }
9654
9655 const CellInfo& VectorOfCellInfo::get(int pos) const
9656 {
9657   if(pos<0 || pos>=(int)_pool.size())
9658     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9659   return _pool[pos];
9660 }
9661
9662 CellInfo& VectorOfCellInfo::get(int pos)
9663 {
9664   if(pos<0 || pos>=(int)_pool.size())
9665     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9666   return _pool[pos];
9667 }
9668
9669 /*!
9670  * Given :
9671  * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9672  * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9673  *
9674  * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9675  *
9676  * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9677  *
9678  * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9679  */
9680 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9681                                          MCAuto<DataArrayInt>& idsLeftRight)
9682 {
9683   int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9684   if(nbCellsInSplitMesh1D==0)
9685     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9686   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9687   std::size_t nb(allEdges.size()),jj;
9688   if(nb%2!=0)
9689     throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9690   std::vector<int> edge1Bis(nb*2);
9691   std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9692   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9693   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9694   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9695   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9696   //
9697   idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9698   int *idsLeftRightPtr(idsLeftRight->getPointer());
9699   VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9700   for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9701     {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9702       int iEnd(iStart);
9703       for(;iEnd<nbCellsInSplitMesh1D;)
9704         {
9705           for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9706           if(jj!=nb)
9707             break;
9708           else
9709             iEnd++;
9710         }
9711       if(iEnd<nbCellsInSplitMesh1D)
9712         iEnd++;
9713       //
9714       MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9715       int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9716       //
9717       MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9718       retTmp->setCoords(splitMesh1D->getCoords());
9719       retTmp->allocateCells();
9720
9721       std::vector< std::vector<int> > out0;
9722       std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9723
9724       BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9725       for(std::size_t cnt=0;cnt<out0.size();cnt++)
9726         AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9727       pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9728       //
9729       iStart=iEnd;
9730     }
9731   for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9732     pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9733   return pool.getZeMesh().retn();
9734 }
9735
9736 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9737                                      const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9738                                      MCAuto<DataArrayInt>& idsLeftRight)
9739 {
9740   const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9741   //
9742   std::vector<int> allEdges;
9743   std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9744   for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9745     {
9746       int edgeId(std::abs(*it)-1);
9747       std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9748       MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9749       const std::vector<int>& edge1(intersectEdge1[edgeId]);
9750       if(*it>0)
9751         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9752       else
9753         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9754       std::size_t sz(edge1.size());
9755       for(std::size_t cnt=0;cnt<sz;cnt++)
9756         allEdgesPtr.push_back(ee);
9757     }
9758   //
9759   return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9760 }
9761
9762 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9763 {
9764   if(!typ1.isQuadratic() && !typ2.isQuadratic())
9765     {//easy case comparison not
9766       return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9767     }
9768   else if(typ1.isQuadratic() && typ2.isQuadratic())
9769     {
9770       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9771       if(!status0)
9772         return false;
9773       if(conn1[2]==conn2[2])
9774         return true;
9775       const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9776       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9777       return dist<eps;
9778     }
9779   else
9780     {//only one is quadratic
9781       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9782       if(!status0)
9783         return false;
9784       const double *a(0),*bb(0),*be(0);
9785       if(typ1.isQuadratic())
9786         {
9787           a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9788         }
9789       else
9790         {
9791           a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9792         }
9793       double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9794       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9795       return dist<eps;
9796     }
9797 }
9798
9799 /*!
9800  * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9801  * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9802  *
9803  * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9804  */
9805 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9806 {
9807   if(candidatesIn2DEnd==candidatesIn2DBg)
9808     throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9809   const double *coo(mesh2DSplit->getCoords()->begin());
9810   if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9811     return *candidatesIn2DBg;
9812   int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9813   MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9814   if(cellIdInMesh1DSplitRelative<0)
9815     cur1D->changeOrientationOfCells();
9816   const int *c1D(cur1D->getNodalConnectivity()->begin());
9817   const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9818   for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9819     {
9820       MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9821       const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9822       const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9823       unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9824       INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9825       for(unsigned it2=0;it2<sz;it2++)
9826         {
9827           INTERP_KERNEL::NormalizedCellType typeOfSon;
9828           cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9829           const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9830           if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9831             return *it;
9832         }
9833     }
9834   throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9835 }
9836
9837 /// @endcond
9838
9839 /*!
9840  * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9841  * Thus the final result contains the aggregation of nodes of \a mesh2D, then nodes of \a mesh1D, then new nodes that are the result of the intersection
9842  * and finaly, in case of quadratic polygon the centers of edges new nodes.
9843  * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9844  *
9845  * \param [in] mesh2D - the 2D mesh (spacedim=meshdim=2) to be intersected using \a mesh1D tool. The mesh must be so that each point in the space covered by \a mesh2D
9846  *                      must be covered exactly by one entity, \b no \b more. If it is not the case, some tools are available to heal the mesh (conformize2D, mergeNodes)
9847  * \param [in] mesh1D - the 1D mesh (spacedim=2 meshdim=1) the is the tool that will be used to intersect \a mesh2D. \a mesh1D must be ordered consecutively. If it is not the case
9848  *                      you can invoke orderConsecutiveCells1D on \a mesh1D.
9849  * \param [in] eps - precision used to perform intersections and localization operations.
9850  * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9851  * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9852  * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9853  *                               So this array has a number of tuples equal to the number of cells of \a splitMesh2D and a number of component equal to 1.
9854  * \param [out] cellIdInMesh1D - the array of pair that gives for each cell id \a i in \a splitMesh1D the cell in \a splitMesh2D on the left for the 1st component
9855  *                               and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9856  *                               So this array has a number of tuples equal to the number of cells of \a splitMesh1D and a number of components equal to 2.
9857  *
9858  * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9859  */
9860 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9861 {
9862   if(!mesh2D || !mesh1D)
9863     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9864   mesh2D->checkFullyDefined();
9865   mesh1D->checkFullyDefined();
9866   const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9867   if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9868     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9869   // Step 1: compute all edge intersections (new nodes)
9870   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9871   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9872   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9873   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9874   //
9875   // Build desc connectivity
9876   DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9877   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9878   MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9879   std::map<int,int> mergedNodes;
9880   Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9881   // use mergeNodes to fix intersectEdge1
9882   for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9883     {
9884       std::size_t n((*it0).size()/2);
9885       int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9886       std::map<int,int>::const_iterator it1;
9887       it1=mergedNodes.find(eltStart);
9888       if(it1!=mergedNodes.end())
9889         (*it0)[0]=(*it1).second;
9890       it1=mergedNodes.find(eltEnd);
9891       if(it1!=mergedNodes.end())
9892         (*it0)[2*n-1]=(*it1).second;
9893     }
9894   //
9895   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9896   addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9897   // Step 2: re-order newly created nodes according to the ordering found in m2
9898   std::vector< std::vector<int> > intersectEdge2;
9899   BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9900   subDiv2.clear();
9901   // Step 3: compute splitMesh1D
9902   MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9903   MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9904   MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9905       idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9906   MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9907   MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9908   // deal with cells in mesh2D that are not cut but only some of their edges are
9909   MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9910   idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9911   idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9912   MCAuto<DataArrayInt> out0s;//ids in mesh2D that are impacted by the fact that some edges of \a mesh1D are part of the edges of those cells
9913   if(!idsInDesc2DToBeRefined->empty())
9914     {
9915       DataArrayInt *out0(0),*outi0(0);
9916       MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9917       MCAuto<DataArrayInt> outi0s(outi0);
9918       out0s=out0;
9919       out0s=out0s->buildUnique();
9920       out0s->sort(true);
9921     }
9922   //
9923   MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9924   MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9925   MCAuto<DataArrayInt> elts,eltsIndex;
9926   mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9927   MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9928   MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9929   if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9930     throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9931   MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9932   MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9933   if((DataArrayInt *)out0s)
9934     untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9935   std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9936   // OK all is ready to insert in ret2 mesh
9937   if(!untouchedCells->empty())
9938     {// the most easy part, cells in mesh2D not impacted at all
9939       outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9940       outMesh2DSplit.back()->setCoords(ret1->getCoords());
9941       ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9942     }
9943   if((DataArrayInt *)out0s)
9944     {// here dealing with cells in out0s but not in cellsToBeModified
9945       MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9946       const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9947       for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9948         {
9949           outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9950           ret1->setCoords(outMesh2DSplit.back()->getCoords());
9951         }
9952       int offset(ret2->getNumberOfTuples());
9953       ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9954       MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9955       partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9956       int kk(0),*ret3ptr(partOfRet3->getPointer());
9957       for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9958         {
9959           int faceId(std::abs(*it)-1);
9960           for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9961             {
9962               int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9963               if(tmp!=-1)
9964                 {
9965                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9966                     ret3ptr[2*kk]=tmp+offset;
9967                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9968                     ret3ptr[2*kk+1]=tmp+offset;
9969                 }
9970               else
9971                 {//the current edge is shared by a 2D cell that will be split just after
9972                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9973                     ret3ptr[2*kk]=-(*it2+1);
9974                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9975                     ret3ptr[2*kk+1]=-(*it2+1);
9976                 }
9977             }
9978         }
9979       m1Desc->setCoords(ret1->getCoords());
9980       ret1NonCol->setCoords(ret1->getCoords());
9981       ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
9982       if(!outMesh2DSplit.empty())
9983         {
9984           DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
9985           for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
9986             (*itt)->setCoords(da);
9987         }
9988     }
9989   cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
9990   for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
9991     {
9992       MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
9993       idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
9994       MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
9995       MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
9996       MCAuto<DataArrayInt> partOfRet3;
9997       MCAuto<MEDCouplingUMesh> splitOfOneCell(BuildMesh2DCutFrom(eps,*it,m1Desc,partOfMesh1CuttingCur2DCell,dd1->begin()+dd2->getIJ(*it,0),dd1->begin()+dd2->getIJ((*it)+1,0),intersectEdge1,ret2->getNumberOfTuples(),partOfRet3));
9998       ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
9999       outMesh2DSplit.push_back(splitOfOneCell);
10000       for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
10001         ret2->pushBackSilent(*it);
10002     }
10003   //
10004   std::size_t nbOfMeshes(outMesh2DSplit.size());
10005   std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10006   for(std::size_t i=0;i<nbOfMeshes;i++)
10007     tmp[i]=outMesh2DSplit[i];
10008   //
10009   ret1->getCoords()->setInfoOnComponents(compNames);
10010   MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10011   // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10012   ret3->rearrange(1);
10013   MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10014   for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10015     {
10016       int old2DCellId(-ret3->getIJ(*it,0)-1);
10017       MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10018       ret3->setIJ(*it,0,FindRightCandidateAmong(ret2D,candidates->begin(),candidates->end(),ret1,*it%2==0?-((*it)/2+1):(*it)/2+1,eps));// div by 2 because 2 components natively in ret3
10019     }
10020   ret3->changeValue(std::numeric_limits<int>::max(),-1);
10021   ret3->rearrange(2);
10022   //
10023   splitMesh1D=ret1.retn();
10024   splitMesh2D=ret2D.retn();
10025   cellIdInMesh2D=ret2.retn();
10026   cellIdInMesh1D=ret3.retn();
10027 }
10028
10029 /**
10030  * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10031  * (newly created) nodes corresponding to the edge intersections.
10032  * Output params:
10033  * @param[out] cr, crI connectivity of the resulting mesh
10034  * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10035  * TODO: describe input parameters
10036  */
10037 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10038                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10039                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10040                                                          const std::vector<double>& addCoords,
10041                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10042 {
10043   static const int SPACEDIM=2;
10044   const double *coo1(m1->getCoords()->getConstPointer());
10045   const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10046   int offset1(m1->getNumberOfNodes());
10047   const double *coo2(m2->getCoords()->getConstPointer());
10048   const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10049   int offset2(offset1+m2->getNumberOfNodes());
10050   int offset3(offset2+((int)addCoords.size())/2);
10051   MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10052   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10053   // Here a BBTree on 2D-cells, not on segments:
10054   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10055   int ncell1(m1->getNumberOfCells());
10056   crI.push_back(0);
10057   for(int i=0;i<ncell1;i++)
10058     {
10059       std::vector<int> candidates2;
10060       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10061       std::map<INTERP_KERNEL::Node *,int> mapp;
10062       std::map<int,INTERP_KERNEL::Node *> mappRev;
10063       INTERP_KERNEL::QuadraticPolygon pol1;
10064       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10065       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10066       // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10067       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10068       // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10069       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10070           desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10071       //
10072       std::set<INTERP_KERNEL::Edge *> edges1;// store all edges of pol1 that are NOT consumed by intersect cells. If any after iteration over candidates2 -> a part of pol1 should appear in result
10073       std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10074       INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10075       for(it1.first();!it1.finished();it1.next())
10076         edges1.insert(it1.current()->getPtr());
10077       //
10078       std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10079       std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10080       int ii=0;
10081       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10082         {
10083           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10084           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10085           // Complete mapping with elements coming from the current cell it2 in mesh2:
10086           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10087           // pol2 is the new QP in the final merged result.
10088           pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10089               pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10090         }
10091       ii=0;
10092       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10093         {
10094           INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10095           pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10096           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10097           pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10098         }
10099       // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10100       // by m2 but that we still want to keep in the final result.
10101       if(!edges1.empty())
10102         {
10103           try
10104           {
10105               INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10106           }
10107           catch(INTERP_KERNEL::Exception& e)
10108           {
10109               std::ostringstream oss; oss << "Error when computing residual of cell #" << i << " in source/m1 mesh ! Maybe the neighbours of this cell in mesh are not well connected !\n" << "The deep reason is the following : " << e.what();
10110               throw INTERP_KERNEL::Exception(oss.str().c_str());
10111           }
10112         }
10113       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10114         (*it).second->decrRef();
10115     }
10116 }
10117
10118 /**
10119  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10120  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10121  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10122  * The caller is to deal with the resulting DataArrayInt.
10123  *  \throw If the coordinate array is not set.
10124  *  \throw If the nodal connectivity of the cells is not defined.
10125  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10126  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10127  *
10128  * \sa DataArrayInt::sortEachPairToMakeALinkedList
10129  */
10130 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10131 {
10132   checkFullyDefined();
10133   if(getMeshDimension()!=1)
10134     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10135
10136   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10137   MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10138   MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10139   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10140   const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10141   const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10142   MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10143   const int * dsi(_dsi->getConstPointer());
10144   MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10145   m_points=0;
10146   if (dsii->getNumberOfTuples())
10147     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10148
10149   int nc(getNumberOfCells());
10150   MCAuto<DataArrayInt> result(DataArrayInt::New());
10151   result->alloc(nc,1);
10152
10153   // set of edges not used so far
10154   std::set<int> edgeSet;
10155   for (int i=0; i<nc; edgeSet.insert(i), i++);
10156
10157   int startSeg=0;
10158   int newIdx=0;
10159   // while we have points with only one neighbor segments
10160   do
10161     {
10162       std::list<int> linePiece;
10163       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10164       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10165         {
10166           // Fill the list forward (resp. backward) from the start segment:
10167           int activeSeg = startSeg;
10168           int prevPointId = -20;
10169           int ptId;
10170           while (!edgeSet.empty())
10171             {
10172               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10173                 {
10174                   if (direction==0)
10175                     linePiece.push_back(activeSeg);
10176                   else
10177                     linePiece.push_front(activeSeg);
10178                   edgeSet.erase(activeSeg);
10179                 }
10180
10181               int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10182               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10183               if (dsi[ptId] == 1) // hitting the end of the line
10184                 break;
10185               prevPointId = ptId;
10186               int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10187               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10188             }
10189         }
10190       // Done, save final piece into DA:
10191       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10192       newIdx += linePiece.size();
10193
10194       // identify next valid start segment (one which is not consumed)
10195       if(!edgeSet.empty())
10196         startSeg = *(edgeSet.begin());
10197     }
10198   while (!edgeSet.empty());
10199   return result.retn();
10200 }
10201
10202 /// @cond INTERNAL
10203
10204 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10205 {
10206   MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10207   std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10208   if(it==m.end())
10209     throw INTERP_KERNEL::Exception("Internal error in remapping !");
10210   int v((*it).second);
10211   if(v==forbVal0 || v==forbVal1)
10212     return ;
10213   if(std::find(isect.begin(),isect.end(),v)==isect.end())
10214     isect.push_back(v);
10215 }
10216
10217 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10218 {
10219   int sz(c.size());
10220   if(sz<=1)
10221     return false;
10222   bool presenceOfOn(false);
10223   for(int i=0;i<sz;i++)
10224     {
10225       INTERP_KERNEL::ElementaryEdge *e(c[i]);
10226       if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10227         continue ;
10228       IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10229       IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10230     }
10231   return presenceOfOn;
10232 }
10233
10234 /// @endcond
10235
10236 /**
10237  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10238  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10239  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10240  * a minimal creation of new nodes is wanted.
10241  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10242  * nodes if a SEG3 is split without information of middle.
10243  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10244  * avoid to have a non conform mesh.
10245  *
10246  * \return int - the number of new nodes created (in most of cases 0).
10247  * 
10248  * \throw If \a this is not coherent.
10249  * \throw If \a this has not spaceDim equal to 2.
10250  * \throw If \a this has not meshDim equal to 2.
10251  * \throw If some subcells needed to be split are orphan.
10252  * \sa MEDCouplingUMesh::conformize2D
10253  */
10254 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10255 {
10256   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10257     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10258   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10259   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10260     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10261   if(midOpt==0 && midOptI==0)
10262     {
10263       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10264       return 0;
10265     }
10266   else if(midOpt!=0 && midOptI!=0)
10267     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10268   else
10269     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10270 }
10271
10272 /*!
10273  * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10274  * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10275  * This method performs a conformization of \b this. So if a edge in \a this can be split into entire edges in \a this this method
10276  * will suppress such edges to use sub edges in \a this. So this method does not add nodes in \a this if merged edges are both linear (INTERP_KERNEL::NORM_SEG2).
10277  * In the other cases new nodes can be created. If any are created, they will be appended at the end of the coordinates object before the invokation of this method.
10278  * 
10279  * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10280  * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10281  *
10282  * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10283  * This method expects that all nodes in \a this are not closer than \a eps.
10284  * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10285  * 
10286  * \param [in] eps the relative error to detect merged edges.
10287  * \return DataArrayInt  * - The list of cellIds in \a this that have been subdivided. If empty, nothing changed in \a this (as if it were a const method). The array is a newly allocated array
10288  *                           that the user is expected to deal with.
10289  *
10290  * \throw If \a this is not coherent.
10291  * \throw If \a this has not spaceDim equal to 2.
10292  * \throw If \a this has not meshDim equal to 2.
10293  * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10294  */
10295 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10296 {
10297   static const int SPACEDIM=2;
10298   checkConsistencyLight();
10299   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10300     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10301   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10302   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10303   const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10304   MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10305   const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10306   int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10307   std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10308   std::vector<double> addCoo;
10309   BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10310   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10311   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10312   for(int i=0;i<nDescCell;i++)
10313     {
10314       std::vector<int> candidates;
10315       myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10316       for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10317         if(*it>i)
10318           {
10319             std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10320             INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10321                 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10322             INTERP_KERNEL::MergePoints merge;
10323             INTERP_KERNEL::QuadraticPolygon c1,c2;
10324             e1->intersectWith(e2,merge,c1,c2);
10325             e1->decrRef(); e2->decrRef();
10326             if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10327               overlapEdge[i].push_back(*it);
10328             if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10329               overlapEdge[*it].push_back(i);
10330           }
10331     }
10332   // splitting done. sort intersect point in intersectEdge.
10333   std::vector< std::vector<int> > middle(nDescCell);
10334   int nbOf2DCellsToBeSplit(0);
10335   bool middleNeedsToBeUsed(false);
10336   std::vector<bool> cells2DToTreat(nDescCell,false);
10337   for(int i=0;i<nDescCell;i++)
10338     {
10339       std::vector<int>& isect(intersectEdge[i]);
10340       int sz((int)isect.size());
10341       if(sz>1)
10342         {
10343           std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10344           INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10345           e->sortSubNodesAbs(coords,isect);
10346           e->decrRef();
10347         }
10348       if(sz!=0)
10349         {
10350           int idx0(rdi[i]),idx1(rdi[i+1]);
10351           if(idx1-idx0!=1)
10352             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10353           if(!cells2DToTreat[rd[idx0]])
10354             {
10355               cells2DToTreat[rd[idx0]]=true;
10356               nbOf2DCellsToBeSplit++;
10357             }
10358           // try to reuse at most eventual 'middle' of SEG3
10359           std::vector<int>& mid(middle[i]);
10360           mid.resize(sz+1,-1);
10361           if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10362             {
10363               middleNeedsToBeUsed=true;
10364               const std::vector<int>& candidates(overlapEdge[i]);
10365               std::vector<int> trueCandidates;
10366               for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10367                 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10368                   trueCandidates.push_back(*itc);
10369               int stNode(c[ci[i]+1]),endNode(isect[0]);
10370               for(int j=0;j<sz+1;j++)
10371                 {
10372                   for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10373                     {
10374                       int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10375                       if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10376                         { mid[j]=*itc; break; }
10377                     }
10378                   stNode=endNode;
10379                   endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10380                 }
10381             }
10382         }
10383     }
10384   MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10385   if(nbOf2DCellsToBeSplit==0)
10386     return ret.retn();
10387   //
10388   int *retPtr(ret->getPointer());
10389   for(int i=0;i<nCell;i++)
10390     if(cells2DToTreat[i])
10391       *retPtr++=i;
10392   //
10393   MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10394   DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10395   MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10396   DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10397   if(middleNeedsToBeUsed)
10398     { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10399   MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10400   int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10401   setCoords(modif->getCoords());//if nbOfNodesCreated==0 modif and this have the same coordinates pointer so this line has no effect. But for quadratic cases this line is important.
10402   setPartOfMySelf(ret->begin(),ret->end(),*modif);
10403   {
10404     bool areNodesMerged; int newNbOfNodes;
10405     if(nbOfNodesCreated!=0)
10406       MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10407   }
10408   return ret.retn();
10409 }
10410
10411 /*!
10412  * This non const method works on 2D mesh. This method scans every cell in \a this and look if each edge constituting this cell is not mergeable with neighbors edges of that cell.
10413  * If yes, the cell is "repaired" to minimize at most its number of edges. So this method do not change the overall shape of cells in \a this (with eps precision).
10414  * This method do not take care of shared edges between cells, so this method can lead to a non conform mesh (\a this). If a conform mesh is required you're expected
10415  * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10416  * This method works on any 2D geometric types of cell (even static one). If a cell is touched its type becomes dynamic automaticaly. For 2D "repaired" quadratic cells
10417  * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10418  *
10419  * If the returned array is empty it means that nothing has changed in \a this (as if it were a const method). If the array is not empty the connectivity of \a this is modified
10420  * using new instance, idem for coordinates.
10421  *
10422  * If \a this is constituted by only linear 2D cells, this method is close to the computation of the convex hull of each cells in \a this.
10423  * 
10424  * \return DataArrayInt  * - The list of cellIds in \a this that have at least one edge colinearized.
10425  *
10426  * \throw If \a this is not coherent.
10427  * \throw If \a this has not spaceDim equal to 2.
10428  * \throw If \a this has not meshDim equal to 2.
10429  * 
10430  * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10431  */
10432 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10433 {
10434   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10435   checkConsistencyLight();
10436   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10437     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10438   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10439   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10440   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10441   const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10442   MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10443   MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10444   const double *coords(_coords->begin());
10445   int *newciptr(newci->getPointer());
10446   for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10447     {
10448       if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10449         ret->pushBackSilent(i);
10450       newciptr[1]=newc->getNumberOfTuples();
10451     }
10452   //
10453   if(ret->empty())
10454     return ret.retn();
10455   if(!appendedCoords->empty())
10456     {
10457       appendedCoords->rearrange(2);
10458       MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10459       //non const part
10460       setCoords(newCoords);
10461     }
10462   //non const part
10463   setConnectivity(newc,newci,true);
10464   return ret.retn();
10465 }
10466
10467 /*!
10468  * \param [out] intersectEdge1 - for each cell in \a m1Desc returns the result of the split. The result is given using pair of int given resp start and stop.
10469  *                               So for all edge \a i in \a m1Desc \a  intersectEdge1[i] is of length 2*n where n is the number of sub edges.
10470  *                               And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10471  * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10472  * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10473  * \param [out] addCoo - nodes to be append at the end
10474  * \param [out] mergedNodes - gives all pair of nodes of \a m2Desc that have same location than some nodes in \a m1Desc. key is id in \a m2Desc offseted and value is id in \a m1Desc.
10475  */
10476 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10477                                          std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2, std::vector<double>& addCoo, std::map<int,int>& mergedNodes)
10478 {
10479   static const int SPACEDIM=2;
10480   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10481   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10482   const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10483   // Build BB tree of all edges in the tool mesh (second mesh)
10484   MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10485   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10486   int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10487   intersectEdge1.resize(nDescCell1);
10488   colinear2.resize(nDescCell2);
10489   subDiv2.resize(nDescCell2);
10490   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10491
10492   std::vector<int> candidates1(1);
10493   int offset1(m1Desc->getNumberOfNodes());
10494   int offset2(offset1+m2Desc->getNumberOfNodes());
10495   for(int i=0;i<nDescCell1;i++)  // for all edges in the first mesh
10496     {
10497       std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10498       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10499       if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10500         {
10501           std::map<INTERP_KERNEL::Node *,int> map1,map2;
10502           // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10503           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10504           candidates1[0]=i;
10505           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10506           // This following part is to avoid that some removed nodes (for example due to a merge between pol1 and pol2) are replaced by a newly created one
10507           // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10508           std::set<INTERP_KERNEL::Node *> nodes;
10509           pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10510           std::size_t szz(nodes.size());
10511           std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10512           std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10513           for(std::size_t iii=0;iii<szz;iii++,itt++)
10514             { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10515           // end of protection
10516           // Performs egde cutting:
10517           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10518           delete pol2;
10519           delete pol1;
10520         }
10521       else
10522         // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10523         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10524     }
10525 }
10526
10527 /*!
10528  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10529  * It builds the descending connectivity of the two meshes, and then using a binary tree
10530  * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10531  * Documentation about parameters  colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10532  */
10533 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10534                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10535                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10536                                                    std::vector<double>& addCoo,
10537                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10538 {
10539   // Build desc connectivity
10540   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10541   desc2=DataArrayInt::New();
10542   descIndx2=DataArrayInt::New();
10543   revDesc2=DataArrayInt::New();
10544   revDescIndx2=DataArrayInt::New();
10545   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10546   MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10547   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10548   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10549   MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10550   std::map<int,int> notUsedMap;
10551   Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10552   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10553   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10554 }
10555
10556 /*!
10557  * This method performs the 2nd step of Partition of 2D mesh.
10558  * This method has 4 inputs :
10559  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10560  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10561  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10562  * The aim of this method is to sort the splitting nodes, if any, and to put them in 'intersectEdge' output parameter based on edges of mesh 'm2'
10563  * Nodes end up lying consecutively on a cutted edge.
10564  * \param m1 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
10565  * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10566  * \param m2 is expected to be a mesh of meshDimension equal to 1 and spaceDim equal to 2. No check of that is performed by this method.
10567  * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10568  * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10569  */
10570 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10571                                            const std::vector<double>& addCoo,
10572                                            const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10573 {
10574   int offset1=m1->getNumberOfNodes();
10575   int ncell=m2->getNumberOfCells();
10576   const int *c=m2->getNodalConnectivity()->getConstPointer();
10577   const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10578   const double *coo=m2->getCoords()->getConstPointer();
10579   const double *cooBis=m1->getCoords()->getConstPointer();
10580   int offset2=offset1+m2->getNumberOfNodes();
10581   intersectEdge.resize(ncell);
10582   for(int i=0;i<ncell;i++,cI++)
10583     {
10584       const std::vector<int>& divs=subDiv[i];
10585       int nnode=cI[1]-cI[0]-1;
10586       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10587       std::map<INTERP_KERNEL::Node *, int> mapp22;
10588       for(int j=0;j<nnode;j++)
10589         {
10590           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10591           int nnid=c[(*cI)+j+1];
10592           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10593           mapp22[nn]=nnid+offset1;
10594         }
10595       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10596       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10597         ((*it).second.first)->decrRef();
10598       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10599       std::map<INTERP_KERNEL::Node *,int> mapp3;
10600       for(std::size_t j=0;j<divs.size();j++)
10601         {
10602           int id=divs[j];
10603           INTERP_KERNEL::Node *tmp=0;
10604           if(id<offset1)
10605             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10606           else if(id<offset2)
10607             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10608           else
10609             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10610           addNodes[j]=tmp;
10611           mapp3[tmp]=id;
10612         }
10613       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10614       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10615         (*it)->decrRef();
10616       e->decrRef();
10617     }
10618 }
10619
10620 /*!
10621  * This method is part of the Slice3D algorithm. It is the first step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
10622  * This method allows to compute given the status of 3D curve cells and the descending connectivity 3DSurf->3DCurve to deduce the intersection of each 3D surf cells
10623  * with a plane. The result will be put in 'cut3DSuf' out parameter.
10624  * \param [in] cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10625  * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10626  * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10627  * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10628  * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10629  * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10630  * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10631  * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10632  * \param [out] cut3DSuf input/output param.
10633  */
10634 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10635                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
10636                                                    const int *desc, const int *descIndx, 
10637                                                    std::vector< std::pair<int,int> >& cut3DSurf)
10638 {
10639   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10640   int nbOf3DSurfCell=(int)cut3DSurf.size();
10641   for(int i=0;i<nbOf3DSurfCell;i++)
10642     {
10643       std::vector<int> res;
10644       int offset=descIndx[i];
10645       int nbOfSeg=descIndx[i+1]-offset;
10646       for(int j=0;j<nbOfSeg;j++)
10647         {
10648           int edgeId=desc[offset+j];
10649           int status=cut3DCurve[edgeId];
10650           if(status!=-2)
10651             {
10652               if(status>-1)
10653                 res.push_back(status);
10654               else
10655                 {
10656                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10657                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10658                 }
10659             }
10660         }
10661       switch(res.size())
10662       {
10663         case 2:
10664           {
10665             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10666             break;
10667           }
10668         case 1:
10669         case 0:
10670           {
10671             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10672             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10673             if(res.size()==2)
10674               {
10675                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10676               }
10677             else
10678               {
10679                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10680               }
10681             break;
10682           }
10683         default:
10684           {// case when plane is on a multi colinear edge of a polyhedron
10685             if((int)res.size()==2*nbOfSeg)
10686               {
10687                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10688               }
10689             else
10690               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10691           }
10692       }
10693     }
10694 }
10695
10696 /*!
10697  * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10698  * This method is part of the Slice3D algorithm. It is the second step of assembly process, ones coordinates have been computed (by MEDCouplingUMesh::split3DCurveWithPlane method).
10699  * This method allows to compute given the result of 3D surf cells with plane and the descending connectivity 3D->3DSurf to deduce the intersection of each 3D cells
10700  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10701  * \param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10702  * \param desc is the descending connectivity 3D->3DSurf
10703  * \param descIndx is the descending connectivity index 3D->3DSurf
10704  */
10705 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10706                                                   const int *desc, const int *descIndx,
10707                                                   DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10708 {
10709   checkFullyDefined();
10710   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10711     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10712   const int *nodal3D=_nodal_connec->getConstPointer();
10713   const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10714   int nbOfCells=getNumberOfCells();
10715   for(int i=0;i<nbOfCells;i++)
10716     {
10717       std::map<int, std::set<int> > m;
10718       int offset=descIndx[i];
10719       int nbOfFaces=descIndx[i+1]-offset;
10720       int start=-1;
10721       int end=-1;
10722       for(int j=0;j<nbOfFaces;j++)
10723         {
10724           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10725           if(p.first!=-1 && p.second!=-1)
10726             {
10727               if(p.first!=-2)
10728                 {
10729                   start=p.first; end=p.second;
10730                   m[p.first].insert(p.second);
10731                   m[p.second].insert(p.first);
10732                 }
10733               else
10734                 {
10735                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10736                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10737                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10738                   INTERP_KERNEL::NormalizedCellType cmsId;
10739                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10740                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
10741                   for(unsigned k=0;k<nbOfNodesSon;k++)
10742                     {
10743                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10744                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10745                     }
10746                 }
10747             }
10748         }
10749       if(m.empty())
10750         continue;
10751       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10752       int prev=end;
10753       while(end!=start)
10754         {
10755           std::map<int, std::set<int> >::const_iterator it=m.find(start);
10756           const std::set<int>& s=(*it).second;
10757           std::set<int> s2; s2.insert(prev);
10758           std::set<int> s3;
10759           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10760           if(s3.size()==1)
10761             {
10762               int val=*s3.begin();
10763               conn.push_back(start);
10764               prev=start;
10765               start=val;
10766             }
10767           else
10768             start=end;
10769         }
10770       conn.push_back(end);
10771       if(conn.size()>3)
10772         {
10773           nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10774           nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10775           cellIds->pushBackSilent(i);
10776         }
10777     }
10778 }
10779
10780 /*!
10781  * 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
10782  * 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
10783  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10784  * 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
10785  * 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.
10786  * 
10787  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10788  */
10789 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10790 {
10791   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10792   if(sz>=4)
10793     {
10794       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10795       if(cm.getDimension()==2)
10796         {
10797           const int *node=nodalConnBg+1;
10798           int startNode=*node++;
10799           double refX=coords[2*startNode];
10800           for(;node!=nodalConnEnd;node++)
10801             {
10802               if(coords[2*(*node)]<refX)
10803                 {
10804                   startNode=*node;
10805                   refX=coords[2*startNode];
10806                 }
10807             }
10808           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10809           refX=1e300;
10810           double tmp1;
10811           double tmp2[2];
10812           double angle0=-M_PI/2;
10813           //
10814           int nextNode=-1;
10815           int prevNode=-1;
10816           double resRef;
10817           double angleNext=0.;
10818           while(nextNode!=startNode)
10819             {
10820               nextNode=-1;
10821               resRef=1e300;
10822               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10823                 {
10824                   if(*node!=tmpOut.back() && *node!=prevNode)
10825                     {
10826                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10827                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10828                       double res;
10829                       if(angleM<=angle0)
10830                         res=angle0-angleM;
10831                       else
10832                         res=angle0-angleM+2.*M_PI;
10833                       if(res<resRef)
10834                         {
10835                           nextNode=*node;
10836                           resRef=res;
10837                           angleNext=angleM;
10838                         }
10839                     }
10840                 }
10841               if(nextNode!=startNode)
10842                 {
10843                   angle0=angleNext-M_PI;
10844                   if(angle0<-M_PI)
10845                     angle0+=2*M_PI;
10846                   prevNode=tmpOut.back();
10847                   tmpOut.push_back(nextNode);
10848                 }
10849             }
10850           std::vector<int> tmp3(2*(sz-1));
10851           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10852           std::copy(nodalConnBg+1,nodalConnEnd,it);
10853           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10854             {
10855               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10856               return false;
10857             }
10858           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10859             {
10860               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10861               return false;
10862             }
10863           else
10864             {
10865               nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10866               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10867               return true;
10868             }
10869         }
10870       else
10871         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10872     }
10873   else
10874     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10875 }
10876
10877 /*!
10878  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10879  * This method will not impact the size of inout parameter \b arrIndx but the size of \b arr will be modified in case of suppression.
10880  * 
10881  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10882  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10883  * \param [in,out] arr array in which the remove operation will be done.
10884  * \param [in,out] arrIndx array in the remove operation will modify
10885  * \param [in] offsetForRemoval (by default 0) offset so that for each i in [0,arrIndx->getNumberOfTuples()-1) removal process will be performed in the following range [arr+arrIndx[i]+offsetForRemoval,arr+arr[i+1])
10886  * \return true if \b arr and \b arrIndx have been modified, false if not.
10887  */
10888 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10889 {
10890   if(!arrIndx || !arr)
10891     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10892   if(offsetForRemoval<0)
10893     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10894   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10895   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10896   int *arrIPtr=arrIndx->getPointer();
10897   *arrIPtr++=0;
10898   int previousArrI=0;
10899   const int *arrPtr=arr->getConstPointer();
10900   std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10901   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10902     {
10903       if(*arrIPtr-previousArrI>offsetForRemoval)
10904         {
10905           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10906             {
10907               if(s.find(*work)==s.end())
10908                 arrOut.push_back(*work);
10909             }
10910         }
10911       previousArrI=*arrIPtr;
10912       *arrIPtr=(int)arrOut.size();
10913     }
10914   if(arr->getNumberOfTuples()==(int)arrOut.size())
10915     return false;
10916   arr->alloc((int)arrOut.size(),1);
10917   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10918   return true;
10919 }
10920
10921 /*!
10922  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10923  * (\ref numbering-indirect).
10924  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10925  * The selection of extraction is done standardly in new2old format.
10926  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10927  *
10928  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10929  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10930  * \param [in] arrIn arr origin array from which the extraction will be done.
10931  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10932  * \param [out] arrOut the resulting array
10933  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10934  * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10935  */
10936 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10937                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10938 {
10939   if(!arrIn || !arrIndxIn)
10940     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10941   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10942   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10943     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10944   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10945   const int *arrInPtr=arrIn->getConstPointer();
10946   const int *arrIndxPtr=arrIndxIn->getConstPointer();
10947   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10948   if(nbOfGrps<0)
10949     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10950   int maxSizeOfArr=arrIn->getNumberOfTuples();
10951   MCAuto<DataArrayInt> arro=DataArrayInt::New();
10952   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10953   arrIo->alloc((int)(sz+1),1);
10954   const int *idsIt=idsOfSelectBg;
10955   int *work=arrIo->getPointer();
10956   *work++=0;
10957   int lgth=0;
10958   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10959     {
10960       if(*idsIt>=0 && *idsIt<nbOfGrps)
10961         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10962       else
10963         {
10964           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10965           throw INTERP_KERNEL::Exception(oss.str().c_str());
10966         }
10967       if(lgth>=work[-1])
10968         *work=lgth;
10969       else
10970         {
10971           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10972           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10973           throw INTERP_KERNEL::Exception(oss.str().c_str());
10974         }
10975     }
10976   arro->alloc(lgth,1);
10977   work=arro->getPointer();
10978   idsIt=idsOfSelectBg;
10979   for(std::size_t i=0;i<sz;i++,idsIt++)
10980     {
10981       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
10982         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
10983       else
10984         {
10985           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
10986           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
10987           throw INTERP_KERNEL::Exception(oss.str().c_str());
10988         }
10989     }
10990   arrOut=arro.retn();
10991   arrIndexOut=arrIo.retn();
10992 }
10993
10994 /*!
10995  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10996  * (\ref numbering-indirect).
10997  * This method returns the result of the extraction ( specified by a set of ids with a slice given by \a idsOfSelectStart, \a idsOfSelectStop and \a idsOfSelectStep ).
10998  * The selection of extraction is done standardly in new2old format.
10999  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
11000  *
11001  * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11002  * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11003  * \param [in] idsOfSelectStep
11004  * \param [in] arrIn arr origin array from which the extraction will be done.
11005  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11006  * \param [out] arrOut the resulting array
11007  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11008  * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11009  */
11010 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11011                                                  DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11012 {
11013   if(!arrIn || !arrIndxIn)
11014     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11015   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11016   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11017     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11018   int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11019   const int *arrInPtr=arrIn->getConstPointer();
11020   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11021   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11022   if(nbOfGrps<0)
11023     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11024   int maxSizeOfArr=arrIn->getNumberOfTuples();
11025   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11026   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11027   arrIo->alloc((int)(sz+1),1);
11028   int idsIt=idsOfSelectStart;
11029   int *work=arrIo->getPointer();
11030   *work++=0;
11031   int lgth=0;
11032   for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11033     {
11034       if(idsIt>=0 && idsIt<nbOfGrps)
11035         lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11036       else
11037         {
11038           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11039           throw INTERP_KERNEL::Exception(oss.str().c_str());
11040         }
11041       if(lgth>=work[-1])
11042         *work=lgth;
11043       else
11044         {
11045           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11046           oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11047           throw INTERP_KERNEL::Exception(oss.str().c_str());
11048         }
11049     }
11050   arro->alloc(lgth,1);
11051   work=arro->getPointer();
11052   idsIt=idsOfSelectStart;
11053   for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11054     {
11055       if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11056         work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11057       else
11058         {
11059           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11060           oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11061           throw INTERP_KERNEL::Exception(oss.str().c_str());
11062         }
11063     }
11064   arrOut=arro.retn();
11065   arrIndexOut=arrIo.retn();
11066 }
11067
11068 /*!
11069  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11070  * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for
11071  * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11072  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11073  *
11074  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11075  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11076  * \param [in] arrIn arr origin array from which the extraction will be done.
11077  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11078  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11079  * \param [in] srcArrIndex index array of \b srcArr
11080  * \param [out] arrOut the resulting array
11081  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11082  * 
11083  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11084  */
11085 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11086                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11087                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11088 {
11089   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11090     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11091   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11092   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11093   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11094   std::vector<bool> v(nbOfTuples,true);
11095   int offset=0;
11096   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11097   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11098   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11099     {
11100       if(*it>=0 && *it<nbOfTuples)
11101         {
11102           v[*it]=false;
11103           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11104         }
11105       else
11106         {
11107           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11108           throw INTERP_KERNEL::Exception(oss.str().c_str());
11109         }
11110     }
11111   srcArrIndexPtr=srcArrIndex->getConstPointer();
11112   arrIo->alloc(nbOfTuples+1,1);
11113   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11114   const int *arrInPtr=arrIn->getConstPointer();
11115   const int *srcArrPtr=srcArr->getConstPointer();
11116   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11117   int *arroPtr=arro->getPointer();
11118   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11119     {
11120       if(v[ii])
11121         {
11122           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11123           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11124         }
11125       else
11126         {
11127           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11128           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11129           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11130         }
11131     }
11132   arrOut=arro.retn();
11133   arrIndexOut=arrIo.retn();
11134 }
11135
11136 /*!
11137  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11138  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11139  *
11140  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11141  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11142  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11143  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11144  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11145  * \param [in] srcArrIndex index array of \b srcArr
11146  * 
11147  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11148  */
11149 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11150                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11151 {
11152   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11153     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11154   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11155   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11156   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11157   int *arrInOutPtr=arrInOut->getPointer();
11158   const int *srcArrPtr=srcArr->getConstPointer();
11159   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11160     {
11161       if(*it>=0 && *it<nbOfTuples)
11162         {
11163           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11164             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11165           else
11166             {
11167               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " id (idsOfSelectBg[" << std::distance(idsOfSelectBg,it)<< "]) is " << *it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11168               throw INTERP_KERNEL::Exception(oss.str().c_str());
11169             }
11170         }
11171       else
11172         {
11173           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11174           throw INTERP_KERNEL::Exception(oss.str().c_str());
11175         }
11176     }
11177 }
11178
11179 /*!
11180  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11181  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11182  * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 looking at arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11183  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11184  * A negative value in \b arrIn means that it is ignored.
11185  * 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.
11186  * 
11187  * \param [in] arrIn arr origin array from which the extraction will be done.
11188  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11189  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11190  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11191  */
11192 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11193 {
11194   int seed=0,nbOfDepthPeelingPerformed=0;
11195   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11196 }
11197
11198 /*!
11199  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11200  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11201  * This method start from id 0 that will be contained in output DataArrayInt. It searches then all neighbors of id0 regarding arrIn[arrIndxIn[0]:arrIndxIn[0+1]].
11202  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11203  * A negative value in \b arrIn means that it is ignored.
11204  * 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.
11205  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11206  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11207  * \param [in] arrIn arr origin array from which the extraction will be done.
11208  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11209  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11210  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11211  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11212  * \sa MEDCouplingUMesh::partitionBySpreadZone
11213  */
11214 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11215 {
11216   nbOfDepthPeelingPerformed=0;
11217   if(!arrIndxIn)
11218     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11219   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11220   if(nbOfTuples<=0)
11221     {
11222       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11223       return ret;
11224     }
11225   //
11226   std::vector<bool> fetched(nbOfTuples,false);
11227   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11228 }
11229
11230 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11231 {
11232   nbOfDepthPeelingPerformed=0;
11233   if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11234     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11235   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11236   std::vector<bool> fetched2(nbOfTuples,false);
11237   int i=0;
11238   for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11239     {
11240       if(*seedElt>=0 && *seedElt<nbOfTuples)
11241         { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11242       else
11243         { std::ostringstream oss; oss << "MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : At pos #" << i << " of seeds value is " << *seedElt << "! Should be in [0," << nbOfTuples << ") !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
11244     }
11245   const int *arrInPtr=arrIn->getConstPointer();
11246   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11247   int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11248   std::vector<int> idsToFetch1(seedBg,seedEnd);
11249   std::vector<int> idsToFetch2;
11250   std::vector<int> *idsToFetch=&idsToFetch1;
11251   std::vector<int> *idsToFetchOther=&idsToFetch2;
11252   while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11253     {
11254       for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11255         for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11256           if(!fetched[*it2])
11257             { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11258       std::swap(idsToFetch,idsToFetchOther);
11259       idsToFetchOther->clear();
11260       nbOfDepthPeelingPerformed++;
11261     }
11262   int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11263   i=0;
11264   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11265   int *retPtr=ret->getPointer();
11266   for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11267     if(*it)
11268       *retPtr++=i;
11269   return ret.retn();
11270 }
11271
11272 /*!
11273  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11274  * This method builds an output pair (\b arrOut,\b arrIndexOut) that is a copy from \b arrIn for all cell ids \b not \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) and for
11275  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11276  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11277  *
11278  * \param [in] start begin of set of ids of the input extraction (included)
11279  * \param [in] end end of set of ids of the input extraction (excluded)
11280  * \param [in] step step of the set of ids in range mode.
11281  * \param [in] arrIn arr origin array from which the extraction will be done.
11282  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11283  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11284  * \param [in] srcArrIndex index array of \b srcArr
11285  * \param [out] arrOut the resulting array
11286  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11287  * 
11288  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11289  */
11290 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11291                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11292                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11293 {
11294   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11295     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11296   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11297   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11298   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11299   int offset=0;
11300   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11301   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11302   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11303   int it=start;
11304   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11305     {
11306       if(it>=0 && it<nbOfTuples)
11307         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11308       else
11309         {
11310           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11311           throw INTERP_KERNEL::Exception(oss.str().c_str());
11312         }
11313     }
11314   srcArrIndexPtr=srcArrIndex->getConstPointer();
11315   arrIo->alloc(nbOfTuples+1,1);
11316   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11317   const int *arrInPtr=arrIn->getConstPointer();
11318   const int *srcArrPtr=srcArr->getConstPointer();
11319   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11320   int *arroPtr=arro->getPointer();
11321   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11322     {
11323       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11324       if(pos<0)
11325         {
11326           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11327           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11328         }
11329       else
11330         {
11331           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11332           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11333         }
11334     }
11335   arrOut=arro.retn();
11336   arrIndexOut=arrIo.retn();
11337 }
11338
11339 /*!
11340  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11341  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11342  *
11343  * \param [in] start begin of set of ids of the input extraction (included)
11344  * \param [in] end end of set of ids of the input extraction (excluded)
11345  * \param [in] step step of the set of ids in range mode.
11346  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11347  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11348  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11349  * \param [in] srcArrIndex index array of \b srcArr
11350  * 
11351  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11352  */
11353 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11354                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11355 {
11356   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11357     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11358   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11359   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11360   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11361   int *arrInOutPtr=arrInOut->getPointer();
11362   const int *srcArrPtr=srcArr->getConstPointer();
11363   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11364   int it=start;
11365   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11366     {
11367       if(it>=0 && it<nbOfTuples)
11368         {
11369           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11370             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11371           else
11372             {
11373               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11374               throw INTERP_KERNEL::Exception(oss.str().c_str());
11375             }
11376         }
11377       else
11378         {
11379           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11380           throw INTERP_KERNEL::Exception(oss.str().c_str());
11381         }
11382     }
11383 }
11384
11385 /*!
11386  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11387  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11388  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11389  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11390  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11391  * 
11392  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11393  */
11394 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11395 {
11396   checkFullyDefined();
11397   int mdim=getMeshDimension();
11398   int spaceDim=getSpaceDimension();
11399   if(mdim!=spaceDim)
11400     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11401   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11402   std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11403   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11404   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11405   ret->setCoords(getCoords());
11406   ret->allocateCells((int)partition.size());
11407   //
11408   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11409     {
11410       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11411       MCAuto<DataArrayInt> cell;
11412       switch(mdim)
11413       {
11414         case 2:
11415           cell=tmp->buildUnionOf2DMesh();
11416           break;
11417         case 3:
11418           cell=tmp->buildUnionOf3DMesh();
11419           break;
11420         default:
11421           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11422       }
11423
11424       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11425     }
11426   //
11427   ret->finishInsertingCells();
11428   return ret.retn();
11429 }
11430
11431 /*!
11432  * This method partitions \b this into contiguous zone.
11433  * This method only needs a well defined connectivity. Coordinates are not considered here.
11434  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11435  */
11436 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11437 {
11438   int nbOfCellsCur=getNumberOfCells();
11439   std::vector<DataArrayInt *> ret;
11440   if(nbOfCellsCur<=0)
11441     return ret;
11442   DataArrayInt *neigh=0,*neighI=0;
11443   computeNeighborsOfCells(neigh,neighI);
11444   MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11445   std::vector<bool> fetchedCells(nbOfCellsCur,false);
11446   std::vector< MCAuto<DataArrayInt> > ret2;
11447   int seed=0;
11448   while(seed<nbOfCellsCur)
11449     {
11450       int nbOfPeelPerformed=0;
11451       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11452       seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11453     }
11454   for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11455     ret.push_back((*it).retn());
11456   return ret;
11457 }
11458
11459 /*!
11460  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11461  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11462  *
11463  * \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.
11464  * \return a newly allocated DataArrayInt to be managed by the caller.
11465  * \throw In case of \a code has not the right format (typically of size 3*n)
11466  */
11467 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11468 {
11469   MCAuto<DataArrayInt> ret=DataArrayInt::New();
11470   std::size_t nb=code.size()/3;
11471   if(code.size()%3!=0)
11472     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11473   ret->alloc((int)nb,2);
11474   int *retPtr=ret->getPointer();
11475   for(std::size_t i=0;i<nb;i++,retPtr+=2)
11476     {
11477       retPtr[0]=code[3*i+2];
11478       retPtr[1]=code[3*i+2]+code[3*i+1];
11479     }
11480   return ret.retn();
11481 }
11482
11483 /*!
11484  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11485  * All cells in \a this are expected to be linear 3D cells.
11486  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11487  * It leads to an increase to number of cells.
11488  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11489  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints 
11490  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11491  *
11492  * \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.
11493  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11494  * \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. 
11495  * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11496  *          an id of old cell producing it. The caller is to delete this array using
11497  *         decrRef() as it is no more needed.
11498  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11499  *
11500  * \warning This method operates on each cells in this independantly ! So it can leads to non conform mesh in returned value ! If you expect to have a conform mesh in output
11501  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11502  * 
11503  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11504  * \throw If \a this is not fully constituted with linear 3D cells.
11505  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11506  */
11507 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11508 {
11509   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11510   checkConnectivityFullyDefined();
11511   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11512     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11513   int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11514   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11515   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11516   int *retPt(ret->getPointer());
11517   MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11518   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11519   const int *oldc(_nodal_connec->begin());
11520   const int *oldci(_nodal_connec_index->begin());
11521   const double *coords(_coords->begin());
11522   for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11523     {
11524       std::vector<int> a; std::vector<double> b;
11525       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11526       std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11527       const int *aa(&a[0]);
11528       if(!b.empty())
11529         {
11530           for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11531             if(*it<0)
11532               *it=(-(*(it))-1+nbNodes);
11533           addPts->insertAtTheEnd(b.begin(),b.end());
11534           nbNodes+=(int)b.size()/3;
11535         }
11536       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11537         newConn->insertAtTheEnd(aa,aa+4);
11538     }
11539   if(!addPts->empty())
11540     {
11541       addPts->rearrange(3);
11542       nbOfAdditionalPoints=addPts->getNumberOfTuples();
11543       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11544       ret0->setCoords(addPts);
11545     }
11546   else
11547     {
11548       nbOfAdditionalPoints=0;
11549       ret0->setCoords(getCoords());
11550     }
11551   ret0->setNodalConnectivity(newConn);
11552   //
11553   ret->computeOffsetsFull();
11554   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11555   return ret0.retn();
11556 }
11557
11558 /*!
11559  * It is the linear part of MEDCouplingUMesh::split2DCells. Here no additionnal nodes will be added in \b this. So coordinates pointer remain unchanged (is not even touch). 
11560  *
11561  * \sa MEDCouplingUMesh::split2DCells
11562  */
11563 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11564 {
11565   checkConnectivityFullyDefined();
11566   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11567   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11568   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11569   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11570   int prevPosOfCi(ciPtr[0]);
11571   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11572     {
11573       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11574       *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11575       for(int j=0;j<sz;j++)
11576         {
11577           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11578           for(int k=0;k<sz2;k++)
11579             *cPtr++=subPtr[offset2+k];
11580           if(j!=sz-1)
11581             *cPtr++=oldConn[prevPosOfCi+j+2];
11582           deltaSz+=sz2;
11583         }
11584       prevPosOfCi=ciPtr[1];
11585       ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11586     }
11587   if(c->end()!=cPtr)
11588     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11589   _nodal_connec->decrRef();
11590   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11591 }
11592
11593 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11594 {
11595   if(id!=-1)
11596     return id;
11597   else
11598     {
11599       int ret(nodesCnter++);
11600       double newPt[2];
11601       e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11602       addCoo.insertAtTheEnd(newPt,newPt+2);
11603       return ret;
11604     }
11605 }
11606
11607 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11608 {
11609   if(id!=-1)
11610     return id;
11611   else
11612     {
11613       int ret(nodesCnter++);
11614       double newPt[2];
11615       e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11616       addCoo.insertAtTheEnd(newPt,newPt+2);
11617       return ret;
11618     }
11619 }
11620
11621
11622 /// @cond INTERNAL
11623
11624 void EnterTheResultOf2DCellFirst(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11625 {
11626   int tmp[3];
11627   int trueStart(start>=0?start:nbOfEdges+start);
11628   tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11629   newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11630   if(linOrArc)
11631     {
11632       if(stp-start>1)
11633         {
11634           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11635           InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11636           middles.push_back(tmp3+offset);
11637         }
11638       else
11639         middles.push_back(connBg[trueStart+nbOfEdges]);
11640     }
11641 }
11642
11643 void EnterTheResultOf2DCellMiddle(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11644 {
11645   int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11646   newConnOfCell->pushBackSilent(tmpEnd);
11647   if(linOrArc)
11648     {
11649       if(stp-start>1)
11650         {
11651           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11652           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11653           middles.push_back(tmp3+offset);
11654         }
11655       else
11656         middles.push_back(connBg[start+nbOfEdges]);
11657     }
11658 }
11659
11660 void EnterTheResultOf2DCellEnd(const INTERP_KERNEL::Edge *e, int start, int stp, int nbOfEdges, bool linOrArc, const double *coords, const int *connBg, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords, std::vector<int>& middles)
11661 {
11662   // only the quadratic point to deal with:
11663   if(linOrArc)
11664     {
11665       if(stp-start>1)
11666         {
11667           int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11668           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11669           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11670           middles.push_back(tmp3+offset);
11671         }
11672       else
11673         middles.push_back(connBg[start+nbOfEdges]);
11674     }
11675 }
11676
11677 /// @endcond
11678
11679 /*!
11680  * Returns true if a colinearization has been found in the given cell. If false is returned the content pushed in \a newConnOfCell is equal to [ \a connBg , \a connEnd ) .
11681  * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11682  */
11683 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11684 {
11685   std::size_t sz(std::distance(connBg,connEnd));
11686   if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11687     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11688   sz--;
11689   INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11690   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11691   unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11692   unsigned nbOfHit(0); // number of fusions operated
11693   int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11694   const unsigned int maxNbOfHit = cm.isQuadratic() ? nbs-2 : nbs-3;  // a quad cell is authorized to end up with only two edges, a linear one has to keep 3 at least
11695   INTERP_KERNEL::NormalizedCellType typeOfSon;
11696   std::vector<int> middles;
11697   bool ret(false);
11698   for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11699     {
11700       cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11701       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11702       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11703       posEndElt = posBaseElt+1;
11704
11705       // Look backward first: are the final edges of the cells colinear with the first ones?
11706       // This initializes posBaseElt.
11707       if(nbOfTurn==0)
11708         {
11709           for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11710             {
11711               cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11712               INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11713               INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11714               bool isColinear=eint->areColinears();
11715               if(isColinear)
11716                 {
11717                   nbOfHit++;
11718                   posBaseElt--;
11719                   ret=true;
11720                 }
11721               delete eint;
11722               eCand->decrRef();
11723               if(!isColinear)
11724                 break;
11725             }
11726         }
11727       // Now move forward:
11728       const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt);  // the first element to be inspected going forward
11729       for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++)  // 2nd condition is to avoid ending with a cell wih one single edge
11730         {
11731           cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11732           INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11733           INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11734           bool isColinear(eint->areColinears());
11735           if(isColinear)
11736             {
11737               nbOfHit++;
11738               posEndElt++;
11739               ret=true;
11740             }
11741           delete eint;
11742           eCand->decrRef();
11743           if(!isColinear)
11744               break;
11745         }
11746       //push [posBaseElt,posEndElt) in newConnOfCell using e
11747       // The if clauses below are (volontary) not mutually exclusive: on a quad cell with 2 edges, the end of the connectivity is also its begining!
11748       if(nbOfTurn==0)
11749         // at the begining of the connectivity (insert type)
11750         EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11751       else if((nbOfHit+nbOfTurn) != (nbs-1))
11752         // in the middle
11753         EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11754       if ((nbOfHit+nbOfTurn) == (nbs-1))
11755         // at the end (only quad points to deal with)
11756         EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11757       posBaseElt=posEndElt;
11758       e->decrRef();
11759     }
11760   if(!middles.empty())
11761     newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11762   return ret;
11763 }
11764
11765 /*!
11766  * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11767  *
11768  * \return  int - the number of new nodes created.
11769  * \sa MEDCouplingUMesh::split2DCells
11770  */
11771 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11772 {
11773   checkConsistencyLight();
11774   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11775   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11776   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11777   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11778   const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11779   const double *oldCoordsPtr(getCoords()->begin());
11780   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11781   int prevPosOfCi(ciPtr[0]);
11782   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11783     {
11784       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11785       for(int j=0;j<sz;j++)
11786         { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11787       *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11788       for(int j=0;j<sz;j++)//loop over subedges of oldConn
11789         {
11790           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11791           if(sz2==0)
11792             {
11793               if(j<sz-1)
11794                 cPtr[1]=oldConn[prevPosOfCi+2+j];
11795               cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11796               continue;
11797             }
11798           std::vector<INTERP_KERNEL::Node *> ns(3);
11799           ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11800           ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11801           ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11802           MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11803           for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11804             {
11805               cPtr[1]=subPtr[offset2+k];
11806               cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11807             }
11808           int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11809           if(j!=sz-1)
11810             { cPtr[1]=tmpEnd; }
11811           cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11812         }
11813       prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11814       ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11815     }
11816   if(c->end()!=cPtr)
11817     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11818   _nodal_connec->decrRef();
11819   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11820   addCoo->rearrange(2);
11821   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11822   setCoords(coo);
11823   return addCoo->getNumberOfTuples();
11824 }
11825
11826 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11827 {
11828   if(nodalConnec && nodalConnecIndex)
11829     {
11830       types.clear();
11831       const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11832       int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11833       if(nbOfElem>0)
11834         for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11835           types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11836     }
11837 }
11838
11839 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11840     _own_cell(true),_cell_id(-1),_nb_cell(0)
11841 {
11842   if(mesh)
11843     {
11844       mesh->incrRef();
11845       _nb_cell=mesh->getNumberOfCells();
11846     }
11847 }
11848
11849 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11850 {
11851   if(_mesh)
11852     _mesh->decrRef();
11853   if(_own_cell)
11854     delete _cell;
11855 }
11856
11857 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11858     _own_cell(false),_cell_id(bg-1),
11859     _nb_cell(end)
11860 {
11861   if(mesh)
11862     mesh->incrRef();
11863 }
11864
11865 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11866 {
11867   _cell_id++;
11868   if(_cell_id<_nb_cell)
11869     {
11870       _cell->next();
11871       return _cell;
11872     }
11873   else
11874     return 0;
11875 }
11876
11877 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11878 {
11879   if(_mesh)
11880     _mesh->incrRef();
11881 }
11882
11883 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11884 {
11885   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11886 }
11887
11888 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11889 {
11890   if(_mesh)
11891     _mesh->decrRef();
11892 }
11893
11894 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11895     _itc(itc),
11896     _bg(bg),_end(end)
11897 {
11898   if(_mesh)
11899     _mesh->incrRef();
11900 }
11901
11902 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11903 {
11904   if(_mesh)
11905     _mesh->decrRef();
11906 }
11907
11908 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11909 {
11910   return _type;
11911 }
11912
11913 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11914 {
11915   return _end-_bg;
11916 }
11917
11918 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11919 {
11920   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11921 }
11922
11923 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11924 {
11925   if(mesh)
11926     {
11927       mesh->incrRef();
11928       _nb_cell=mesh->getNumberOfCells();
11929     }
11930 }
11931
11932 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11933 {
11934   if(_mesh)
11935     _mesh->decrRef();
11936   delete _cell;
11937 }
11938
11939 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11940 {
11941   const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11942   const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11943   if(_cell_id<_nb_cell)
11944     {
11945       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11946       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11947       int startId=_cell_id;
11948       _cell_id+=nbOfElems;
11949       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11950     }
11951   else
11952     return 0;
11953 }
11954
11955 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11956 {
11957   if(mesh)
11958     {
11959       _conn=mesh->getNodalConnectivity()->getPointer();
11960       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11961     }
11962 }
11963
11964 void MEDCouplingUMeshCell::next()
11965 {
11966   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11967     {
11968       _conn+=_conn_lgth;
11969       _conn_indx++;
11970     }
11971   _conn_lgth=_conn_indx[1]-_conn_indx[0];
11972 }
11973
11974 std::string MEDCouplingUMeshCell::repr() const
11975 {
11976   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11977     {
11978       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
11979       oss << " : ";
11980       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
11981       return oss.str();
11982     }
11983   else
11984     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
11985 }
11986
11987 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
11988 {
11989   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11990     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
11991   else
11992     return INTERP_KERNEL::NORM_ERROR;
11993 }
11994
11995 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
11996 {
11997   lgth=_conn_lgth;
11998   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11999     return _conn;
12000   else
12001     return 0;
12002 }