Salome HOME
Get relevant changes from V7_dev branch (copyright update, adm files etc)
[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  * \return \c true if at least one cell has been converted, \c false else. In the
1281  *         last case the nodal connectivity remains unchanged.
1282  * \throw If the coordinates array is not set.
1283  * \throw If the nodal connectivity of cells is not defined.
1284  * \throw If \a this->getMeshDimension() < 0.
1285  */
1286 bool MEDCouplingUMesh::unPolyze()
1287 {
1288   checkFullyDefined();
1289   int mdim=getMeshDimension();
1290   if(mdim<0)
1291     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::unPolyze works on umeshes with meshdim equals to 0, 1 2 or 3 !");
1292   if(mdim<=1)
1293     return false;
1294   int nbOfCells=getNumberOfCells();
1295   if(nbOfCells<1)
1296     return false;
1297   int initMeshLgth=getNodalConnectivityArrayLen();
1298   int *conn=_nodal_connec->getPointer();
1299   int *index=_nodal_connec_index->getPointer();
1300   int posOfCurCell=0;
1301   int newPos=0;
1302   int lgthOfCurCell;
1303   bool ret=false;
1304   for(int i=0;i<nbOfCells;i++)
1305     {
1306       lgthOfCurCell=index[i+1]-posOfCurCell;
1307       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
1308       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
1309       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::NORM_ERROR;
1310       int newLgth;
1311       if(cm.isDynamic())
1312         {
1313           switch(cm.getDimension())
1314           {
1315             case 2:
1316               {
1317                 INTERP_KERNEL::AutoPtr<int> tmp=new int[lgthOfCurCell-1];
1318                 std::copy(conn+posOfCurCell+1,conn+posOfCurCell+lgthOfCurCell,(int *)tmp);
1319                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly2D(cm.isQuadratic(),tmp,lgthOfCurCell-1,conn+newPos+1,newLgth);
1320                 break;
1321               }
1322             case 3:
1323               {
1324                 int nbOfFaces,lgthOfPolyhConn;
1325                 INTERP_KERNEL::AutoPtr<int> zipFullReprOfPolyh=INTERP_KERNEL::CellSimplify::getFullPolyh3DCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,nbOfFaces,lgthOfPolyhConn);
1326                 newType=INTERP_KERNEL::CellSimplify::tryToUnPoly3D(zipFullReprOfPolyh,nbOfFaces,lgthOfPolyhConn,conn+newPos+1,newLgth);
1327                 break;
1328               }
1329             case 1:
1330               {
1331                 newType=(lgthOfCurCell==3)?INTERP_KERNEL::NORM_SEG2:INTERP_KERNEL::NORM_POLYL;
1332                 break;
1333               }
1334           }
1335           ret=ret || (newType!=type);
1336           conn[newPos]=newType;
1337           newPos+=newLgth+1;
1338           posOfCurCell=index[i+1];
1339           index[i+1]=newPos;
1340         }
1341       else
1342         {
1343           std::copy(conn+posOfCurCell,conn+posOfCurCell+lgthOfCurCell,conn+newPos);
1344           newPos+=lgthOfCurCell;
1345           posOfCurCell+=lgthOfCurCell;
1346           index[i+1]=newPos;
1347         }
1348     }
1349   if(newPos!=initMeshLgth)
1350     _nodal_connec->reAlloc(newPos);
1351   if(ret)
1352     computeTypes();
1353   return ret;
1354 }
1355
1356 /*!
1357  * This method expects that spaceDimension is equal to 3 and meshDimension equal to 3.
1358  * This method performs operation only on polyhedrons in \b this. If no polyhedrons exists in \b this, \b this remains unchanged.
1359  * This method allows to merge if any coplanar 3DSurf cells that may appear in some polyhedrons cells. 
1360  *
1361  * \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 
1362  *             precision.
1363  */
1364 void MEDCouplingUMesh::simplifyPolyhedra(double eps)
1365 {
1366   checkFullyDefined();
1367   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
1368     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplifyPolyhedra : works on meshdimension 3 and spaceDimension 3 !");
1369   MCAuto<DataArrayDouble> coords=getCoords()->deepCopy();
1370   coords->recenterForMaxPrecision(eps);
1371   //
1372   int nbOfCells=getNumberOfCells();
1373   const int *conn=_nodal_connec->getConstPointer();
1374   const int *index=_nodal_connec_index->getConstPointer();
1375   MCAuto<DataArrayInt> connINew=DataArrayInt::New();
1376   connINew->alloc(nbOfCells+1,1);
1377   int *connINewPtr=connINew->getPointer(); *connINewPtr++=0;
1378   MCAuto<DataArrayInt> connNew=DataArrayInt::New(); connNew->alloc(0,1);
1379   bool changed=false;
1380   for(int i=0;i<nbOfCells;i++,connINewPtr++)
1381     {
1382       if(conn[index[i]]==(int)INTERP_KERNEL::NORM_POLYHED)
1383         {
1384           SimplifyPolyhedronCell(eps,coords,conn+index[i],conn+index[i+1],connNew);
1385           changed=true;
1386         }
1387       else
1388         connNew->insertAtTheEnd(conn+index[i],conn+index[i+1]);
1389       *connINewPtr=connNew->getNumberOfTuples();
1390     }
1391   if(changed)
1392     setConnectivity(connNew,connINew,false);
1393 }
1394
1395 /*!
1396  * This method returns all node ids used in the connectivity of \b this. The data array returned has to be dealt by the caller.
1397  * The returned node ids are sorted ascendingly. This method is close to MEDCouplingUMesh::getNodeIdsInUse except
1398  * the format of the returned DataArrayInt instance.
1399  * 
1400  * \return a newly allocated DataArrayInt sorted ascendingly of fetched node ids.
1401  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1402  */
1403 DataArrayInt *MEDCouplingUMesh::computeFetchedNodeIds() const
1404 {
1405   checkConnectivityFullyDefined();
1406   int nbOfCells=getNumberOfCells();
1407   const int *connIndex=_nodal_connec_index->getConstPointer();
1408   const int *conn=_nodal_connec->getConstPointer();
1409   const int *maxEltPt=std::max_element(_nodal_connec->begin(),_nodal_connec->end());
1410   int maxElt=maxEltPt==_nodal_connec->end()?0:std::abs(*maxEltPt)+1;
1411   std::vector<bool> retS(maxElt,false);
1412   for(int i=0;i<nbOfCells;i++)
1413     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1414       if(conn[j]>=0)
1415         retS[conn[j]]=true;
1416   int sz=0;
1417   for(int i=0;i<maxElt;i++)
1418     if(retS[i])
1419       sz++;
1420   DataArrayInt *ret=DataArrayInt::New();
1421   ret->alloc(sz,1);
1422   int *retPtr=ret->getPointer();
1423   for(int i=0;i<maxElt;i++)
1424     if(retS[i])
1425       *retPtr++=i;
1426   return ret;
1427 }
1428
1429 /*!
1430  * \param [in,out] nodeIdsInUse an array of size typically equal to nbOfNodes.
1431  * \sa MEDCouplingUMesh::getNodeIdsInUse, areAllNodesFetched
1432  */
1433 void MEDCouplingUMesh::computeNodeIdsAlg(std::vector<bool>& nodeIdsInUse) const
1434 {
1435   int nbOfNodes((int)nodeIdsInUse.size()),nbOfCells(getNumberOfCells());
1436   const int *connIndex(_nodal_connec_index->getConstPointer()),*conn(_nodal_connec->getConstPointer());
1437   for(int i=0;i<nbOfCells;i++)
1438     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1439       if(conn[j]>=0)
1440         {
1441           if(conn[j]<nbOfNodes)
1442             nodeIdsInUse[conn[j]]=true;
1443           else
1444             {
1445               std::ostringstream oss; oss << "MEDCouplingUMesh::computeNodeIdsAlg : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1446               throw INTERP_KERNEL::Exception(oss.str().c_str());
1447             }
1448         }
1449 }
1450
1451 /*!
1452  * Finds nodes not used in any cell and returns an array giving a new id to every node
1453  * by excluding the unused nodes, for which the array holds -1. The result array is
1454  * a mapping in "Old to New" mode. 
1455  *  \param [out] nbrOfNodesInUse - number of node ids present in the nodal connectivity.
1456  *  \return DataArrayInt * - a new instance of DataArrayInt. Its length is \a
1457  *          this->getNumberOfNodes(). It holds for each node of \a this mesh either -1
1458  *          if the node is unused or a new id else. The caller is to delete this
1459  *          array using decrRef() as it is no more needed.  
1460  *  \throw If the coordinates array is not set.
1461  *  \throw If the nodal connectivity of cells is not defined.
1462  *  \throw If the nodal connectivity includes an invalid id.
1463  *
1464  *  \if ENABLE_EXAMPLES
1465  *  \ref cpp_mcumesh_getNodeIdsInUse "Here is a C++ example".<br>
1466  *  \ref  py_mcumesh_getNodeIdsInUse "Here is a Python example".
1467  *  \endif
1468  * \sa computeFetchedNodeIds, computeNodeIdsAlg()
1469  */
1470 DataArrayInt *MEDCouplingUMesh::getNodeIdsInUse(int& nbrOfNodesInUse) const
1471 {
1472   nbrOfNodesInUse=-1;
1473   int nbOfNodes(getNumberOfNodes());
1474   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1475   ret->alloc(nbOfNodes,1);
1476   int *traducer=ret->getPointer();
1477   std::fill(traducer,traducer+nbOfNodes,-1);
1478   int nbOfCells=getNumberOfCells();
1479   const int *connIndex=_nodal_connec_index->getConstPointer();
1480   const int *conn=_nodal_connec->getConstPointer();
1481   for(int i=0;i<nbOfCells;i++)
1482     for(int j=connIndex[i]+1;j<connIndex[i+1];j++)
1483       if(conn[j]>=0)
1484         {
1485           if(conn[j]<nbOfNodes)
1486             traducer[conn[j]]=1;
1487           else
1488             {
1489               std::ostringstream oss; oss << "MEDCouplingUMesh::getNodeIdsInUse : In cell #" << i  << " presence of node id " <<  conn[j] << " not in [0," << nbOfNodes << ") !";
1490               throw INTERP_KERNEL::Exception(oss.str().c_str());
1491             }
1492         }
1493   nbrOfNodesInUse=(int)std::count(traducer,traducer+nbOfNodes,1);
1494   std::transform(traducer,traducer+nbOfNodes,traducer,MEDCouplingAccVisit());
1495   return ret.retn();
1496 }
1497
1498 /*!
1499  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1500  * For each cell in \b this the number of nodes constituting cell is computed.
1501  * For each polyhedron cell, the sum of the number of nodes of each face constituting polyhedron cell is returned.
1502  * So for pohyhedrons some nodes can be counted several times in the returned result.
1503  * 
1504  * \return a newly allocated array
1505  * \sa MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell
1506  */
1507 DataArrayInt *MEDCouplingUMesh::computeNbOfNodesPerCell() const
1508 {
1509   checkConnectivityFullyDefined();
1510   int nbOfCells=getNumberOfCells();
1511   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1512   ret->alloc(nbOfCells,1);
1513   int *retPtr=ret->getPointer();
1514   const int *conn=getNodalConnectivity()->getConstPointer();
1515   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1516   for(int i=0;i<nbOfCells;i++,retPtr++)
1517     {
1518       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1519         *retPtr=connI[i+1]-connI[i]-1;
1520       else
1521         *retPtr=connI[i+1]-connI[i]-1-std::count(conn+connI[i]+1,conn+connI[i+1],-1);
1522     }
1523   return ret.retn();
1524 }
1525
1526 /*!
1527  * This method computes effective number of nodes per cell. That is to say nodes appearing several times in nodal connectivity of a cell,
1528  * will be counted only once here whereas it will be counted several times in MEDCouplingUMesh::computeNbOfNodesPerCell method.
1529  *
1530  * \return DataArrayInt * - new object to be deallocated by the caller.
1531  * \sa MEDCouplingUMesh::computeNbOfNodesPerCell
1532  */
1533 DataArrayInt *MEDCouplingUMesh::computeEffectiveNbOfNodesPerCell() const
1534 {
1535   checkConnectivityFullyDefined();
1536   int nbOfCells=getNumberOfCells();
1537   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1538   ret->alloc(nbOfCells,1);
1539   int *retPtr=ret->getPointer();
1540   const int *conn=getNodalConnectivity()->getConstPointer();
1541   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1542   for(int i=0;i<nbOfCells;i++,retPtr++)
1543     {
1544       std::set<int> s(conn+connI[i]+1,conn+connI[i+1]);
1545       if(conn[connI[i]]!=(int)INTERP_KERNEL::NORM_POLYHED)
1546         *retPtr=(int)s.size();
1547       else
1548         {
1549           s.erase(-1);
1550           *retPtr=(int)s.size();
1551         }
1552     }
1553   return ret.retn();
1554 }
1555
1556 /*!
1557  * This method returns a newly allocated array containing this->getNumberOfCells() tuples and 1 component.
1558  * For each cell in \b this the number of faces constituting (entity of dimension this->getMeshDimension()-1) cell is computed.
1559  * 
1560  * \return a newly allocated array
1561  */
1562 DataArrayInt *MEDCouplingUMesh::computeNbOfFacesPerCell() const
1563 {
1564   checkConnectivityFullyDefined();
1565   int nbOfCells=getNumberOfCells();
1566   MCAuto<DataArrayInt> ret=DataArrayInt::New();
1567   ret->alloc(nbOfCells,1);
1568   int *retPtr=ret->getPointer();
1569   const int *conn=getNodalConnectivity()->getConstPointer();
1570   const int *connI=getNodalConnectivityIndex()->getConstPointer();
1571   for(int i=0;i<nbOfCells;i++,retPtr++,connI++)
1572     {
1573       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]);
1574       *retPtr=cm.getNumberOfSons2(conn+connI[0]+1,connI[1]-connI[0]-1);
1575     }
1576   return ret.retn();
1577 }
1578
1579 /*!
1580  * Removes unused nodes (the node coordinates array is shorten) and returns an array
1581  * mapping between new and old node ids in "Old to New" mode. -1 values in the returned
1582  * array mean that the corresponding old node is no more used. 
1583  *  \return DataArrayInt * - a new instance of DataArrayInt of length \a
1584  *           this->getNumberOfNodes() before call of this method. The caller is to
1585  *           delete this array using decrRef() as it is no more needed. 
1586  *  \throw If the coordinates array is not set.
1587  *  \throw If the nodal connectivity of cells is not defined.
1588  *  \throw If the nodal connectivity includes an invalid id.
1589  *  \sa areAllNodesFetched
1590  *
1591  *  \if ENABLE_EXAMPLES
1592  *  \ref cpp_mcumesh_zipCoordsTraducer "Here is a C++ example".<br>
1593  *  \ref  py_mcumesh_zipCoordsTraducer "Here is a Python example".
1594  *  \endif
1595  */
1596 DataArrayInt *MEDCouplingUMesh::zipCoordsTraducer()
1597 {
1598   return MEDCouplingPointSet::zipCoordsTraducer();
1599 }
1600
1601 /*!
1602  * This method stands if 'cell1' and 'cell2' are equals regarding 'compType' policy.
1603  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1604  */
1605 int MEDCouplingUMesh::AreCellsEqual(const int *conn, const int *connI, int cell1, int cell2, int compType)
1606 {
1607   switch(compType)
1608   {
1609     case 0:
1610       return AreCellsEqualPolicy0(conn,connI,cell1,cell2);
1611     case 1:
1612       return AreCellsEqualPolicy1(conn,connI,cell1,cell2);
1613     case 2:
1614       return AreCellsEqualPolicy2(conn,connI,cell1,cell2);
1615     case 3:
1616       return AreCellsEqualPolicy2NoType(conn,connI,cell1,cell2);
1617     case 7:
1618       return AreCellsEqualPolicy7(conn,connI,cell1,cell2);
1619   }
1620   throw INTERP_KERNEL::Exception("Unknown comparison asked ! Must be in 0,1,2,3 or 7.");
1621 }
1622
1623 /*!
1624  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 0.
1625  */
1626 int MEDCouplingUMesh::AreCellsEqualPolicy0(const int *conn, const int *connI, int cell1, int cell2)
1627 {
1628   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1629     return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;
1630   return 0;
1631 }
1632
1633 /*!
1634  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 1.
1635  */
1636 int MEDCouplingUMesh::AreCellsEqualPolicy1(const int *conn, const int *connI, int cell1, int cell2)
1637 {
1638   int sz=connI[cell1+1]-connI[cell1];
1639   if(sz==connI[cell2+1]-connI[cell2])
1640     {
1641       if(conn[connI[cell1]]==conn[connI[cell2]])
1642         {
1643           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1644           unsigned dim=cm.getDimension();
1645           if(dim!=3)
1646             {
1647               if(dim!=1)
1648                 {
1649                   int sz1=2*(sz-1);
1650                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1651                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1652                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1653                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1654                   return work!=tmp+sz1?1:0;
1655                 }
1656               else
1657                 return std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1)?1:0;//case of SEG2 and SEG3
1658             }
1659           else
1660             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy1 : not implemented yet for meshdim == 3 !");
1661         }
1662     }
1663   return 0;
1664 }
1665
1666 /*!
1667  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 2.
1668  */
1669 int MEDCouplingUMesh::AreCellsEqualPolicy2(const int *conn, const int *connI, int cell1, int cell2)
1670 {
1671   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1672     {
1673       if(conn[connI[cell1]]==conn[connI[cell2]])
1674         {
1675           std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1676           std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1677           return s1==s2?1:0;
1678         }
1679     }
1680   return 0;
1681 }
1682
1683 /*!
1684  * This method is less restrictive than AreCellsEqualPolicy2. Here the geometric type is absolutely not taken into account !
1685  */
1686 int MEDCouplingUMesh::AreCellsEqualPolicy2NoType(const int *conn, const int *connI, int cell1, int cell2)
1687 {
1688   if(connI[cell1+1]-connI[cell1]==connI[cell2+1]-connI[cell2])
1689     {
1690       std::set<int> s1(conn+connI[cell1]+1,conn+connI[cell1+1]);
1691       std::set<int> s2(conn+connI[cell2]+1,conn+connI[cell2+1]);
1692       return s1==s2?1:0;
1693     }
1694   return 0;
1695 }
1696
1697 /*!
1698  * This method is the last step of the MEDCouplingPointSet::zipConnectivityTraducer with policy 7.
1699  */
1700 int MEDCouplingUMesh::AreCellsEqualPolicy7(const int *conn, const int *connI, int cell1, int cell2)
1701 {
1702   int sz=connI[cell1+1]-connI[cell1];
1703   if(sz==connI[cell2+1]-connI[cell2])
1704     {
1705       if(conn[connI[cell1]]==conn[connI[cell2]])
1706         {
1707           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[cell1]]);
1708           unsigned dim=cm.getDimension();
1709           if(dim!=3)
1710             {
1711               if(dim!=1)
1712                 {
1713                   int sz1=2*(sz-1);
1714                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz1];
1715                   int *work=std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],(int *)tmp);
1716                   std::copy(conn+connI[cell1]+1,conn+connI[cell1+1],work);
1717                   work=std::search((int *)tmp,(int *)tmp+sz1,conn+connI[cell2]+1,conn+connI[cell2+1]);
1718                   if(work!=tmp+sz1)
1719                     return 1;
1720                   else
1721                     {
1722                       std::reverse_iterator<int *> it1((int *)tmp+sz1);
1723                       std::reverse_iterator<int *> it2((int *)tmp);
1724                       if(std::search(it1,it2,conn+connI[cell2]+1,conn+connI[cell2+1])!=it2)
1725                         return 2;
1726                       else
1727                         return 0;
1728                     }
1729
1730                   return work!=tmp+sz1?1:0;
1731                 }
1732               else
1733                 {//case of SEG2 and SEG3
1734                   if(std::equal(conn+connI[cell1]+1,conn+connI[cell1+1],conn+connI[cell2]+1))
1735                     return 1;
1736                   if(!cm.isQuadratic())
1737                     {
1738                       std::reverse_iterator<const int *> it1(conn+connI[cell1+1]);
1739                       std::reverse_iterator<const int *> it2(conn+connI[cell1]+1);
1740                       if(std::equal(it1,it2,conn+connI[cell2]+1))
1741                         return 2;
1742                       return 0;
1743                     }
1744                   else
1745                     {
1746                       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])
1747                         return 2;
1748                       return 0;
1749                     }
1750                 }
1751             }
1752           else
1753             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AreCellsEqualPolicy7 : not implemented yet for meshdim == 3 !");
1754         }
1755     }
1756   return 0;
1757 }
1758
1759 /*!
1760  * This method find in candidate pool defined by 'candidates' the cells equal following the polycy 'compType'.
1761  * If any true is returned and the results will be put at the end of 'result' output parameter. If not false is returned
1762  * and result remains unchanged.
1763  * The semantic of 'compType' is specified in MEDCouplingPointSet::zipConnectivityTraducer method.
1764  * If in 'candidates' pool -1 value is considered as an empty value.
1765  * WARNING this method returns only ONE set of result !
1766  */
1767 bool MEDCouplingUMesh::AreCellsEqualInPool(const std::vector<int>& candidates, int compType, const int *conn, const int *connI, DataArrayInt *result)
1768 {
1769   if(candidates.size()<1)
1770     return false;
1771   bool ret=false;
1772   std::vector<int>::const_iterator iter=candidates.begin();
1773   int start=(*iter++);
1774   for(;iter!=candidates.end();iter++)
1775     {
1776       int status=AreCellsEqual(conn,connI,start,*iter,compType);
1777       if(status!=0)
1778         {
1779           if(!ret)
1780             {
1781               result->pushBackSilent(start);
1782               ret=true;
1783             }
1784           if(status==1)
1785             result->pushBackSilent(*iter);
1786           else
1787             result->pushBackSilent(status==2?(*iter+1):-(*iter+1));
1788         }
1789     }
1790   return ret;
1791 }
1792
1793 /*!
1794  * This method find cells that are equal (regarding \a compType) in \a this. The comparison is specified
1795  * by \a compType.
1796  * This method keeps the coordiantes of \a this. This method is time consuming.
1797  *
1798  * \param [in] compType input specifying the technique used to compare cells each other.
1799  *   - 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.
1800  *   - 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)
1801  * and their type equal. For 1D mesh the policy 1 is equivalent to 0.
1802  *   - 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
1803  * can be used for users not sensitive to orientation of cell
1804  * \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.
1805  * \param [out] commonCellsArr common cells ids (\ref numbering-indirect)
1806  * \param [out] commonCellsIArr common cells ids (\ref numbering-indirect)
1807  * \return the correspondance array old to new in a newly allocated array.
1808  * 
1809  */
1810 void MEDCouplingUMesh::findCommonCells(int compType, int startCellId, DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr) const
1811 {
1812   MCAuto<DataArrayInt> revNodal=DataArrayInt::New(),revNodalI=DataArrayInt::New();
1813   getReverseNodalConnectivity(revNodal,revNodalI);
1814   FindCommonCellsAlg(compType,startCellId,_nodal_connec,_nodal_connec_index,revNodal,revNodalI,commonCellsArr,commonCellsIArr);
1815 }
1816
1817 void MEDCouplingUMesh::FindCommonCellsAlg(int compType, int startCellId, const DataArrayInt *nodal, const DataArrayInt *nodalI, const DataArrayInt *revNodal, const DataArrayInt *revNodalI,
1818                                           DataArrayInt *& commonCellsArr, DataArrayInt *& commonCellsIArr)
1819 {
1820   MCAuto<DataArrayInt> commonCells=DataArrayInt::New(),commonCellsI=DataArrayInt::New(); commonCells->alloc(0,1);
1821   int nbOfCells=nodalI->getNumberOfTuples()-1;
1822   commonCellsI->reserve(1); commonCellsI->pushBackSilent(0);
1823   const int *revNodalPtr=revNodal->getConstPointer(),*revNodalIPtr=revNodalI->getConstPointer();
1824   const int *connPtr=nodal->getConstPointer(),*connIPtr=nodalI->getConstPointer();
1825   std::vector<bool> isFetched(nbOfCells,false);
1826   if(startCellId==0)
1827     {
1828       for(int i=0;i<nbOfCells;i++)
1829         {
1830           if(!isFetched[i])
1831             {
1832               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1833               std::vector<int> v,v2;
1834               if(connOfNode!=connPtr+connIPtr[i+1])
1835                 {
1836                   const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1837                   v2.insert(v2.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1]);
1838                   connOfNode++;
1839                 }
1840               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1841                 if(*connOfNode>=0)
1842                   {
1843                     v=v2;
1844                     const int *locRevNodal=std::find(revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],i);
1845                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),locRevNodal,revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1846                     v2.resize(std::distance(v2.begin(),it));
1847                   }
1848               if(v2.size()>1)
1849                 {
1850                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1851                     {
1852                       int pos=commonCellsI->back();
1853                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1854                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1855                         isFetched[*it]=true;
1856                     }
1857                 }
1858             }
1859         }
1860     }
1861   else
1862     {
1863       for(int i=startCellId;i<nbOfCells;i++)
1864         {
1865           if(!isFetched[i])
1866             {
1867               const int *connOfNode=std::find_if(connPtr+connIPtr[i]+1,connPtr+connIPtr[i+1],std::bind2nd(std::not_equal_to<int>(),-1));
1868               std::vector<int> v,v2;
1869               if(connOfNode!=connPtr+connIPtr[i+1])
1870                 {
1871                   v2.insert(v2.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1]);
1872                   connOfNode++;
1873                 }
1874               for(;connOfNode!=connPtr+connIPtr[i+1] && v2.size()>1;connOfNode++)
1875                 if(*connOfNode>=0)
1876                   {
1877                     v=v2;
1878                     std::vector<int>::iterator it=std::set_intersection(v.begin(),v.end(),revNodalPtr+revNodalIPtr[*connOfNode],revNodalPtr+revNodalIPtr[*connOfNode+1],v2.begin());
1879                     v2.resize(std::distance(v2.begin(),it));
1880                   }
1881               if(v2.size()>1)
1882                 {
1883                   if(AreCellsEqualInPool(v2,compType,connPtr,connIPtr,commonCells))
1884                     {
1885                       int pos=commonCellsI->back();
1886                       commonCellsI->pushBackSilent(commonCells->getNumberOfTuples());
1887                       for(const int *it=commonCells->begin()+pos;it!=commonCells->end();it++)
1888                         isFetched[*it]=true;
1889                     }
1890                 }
1891             }
1892         }
1893     }
1894   commonCellsArr=commonCells.retn();
1895   commonCellsIArr=commonCellsI.retn();
1896 }
1897
1898 /*!
1899  * Checks if \a this mesh includes all cells of an \a other mesh, and returns an array
1900  * giving for each cell of the \a other an id of a cell in \a this mesh. A value larger
1901  * than \a other->getNumberOfCells() in the returned array means that there is no
1902  * corresponding cell in \a this mesh.
1903  * It is expected that \a this and \a other meshes share the same node coordinates
1904  * array, if it is not so an exception is thrown. 
1905  *  \param [in] other - the mesh to compare with.
1906  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
1907  *         valid values [0,1,2], see zipConnectivityTraducer().
1908  *  \param [out] arr - a new instance of DataArrayInt returning correspondence
1909  *         between cells of the two meshes. It contains \a other->getNumberOfCells()
1910  *         values. The caller is to delete this array using
1911  *         decrRef() as it is no more needed.
1912  *  \return bool - \c true if all cells of \a other mesh are present in the \a this
1913  *         mesh.
1914  *
1915  *  \if ENABLE_EXAMPLES
1916  *  \ref cpp_mcumesh_areCellsIncludedIn "Here is a C++ example".<br>
1917  *  \ref  py_mcumesh_areCellsIncludedIn "Here is a Python example".
1918  *  \endif
1919  *  \sa checkDeepEquivalOnSameNodesWith()
1920  *  \sa checkGeoEquivalWith()
1921  */
1922 bool MEDCouplingUMesh::areCellsIncludedIn(const MEDCouplingUMesh *other, int compType, DataArrayInt *& arr) const
1923 {
1924   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1925   int nbOfCells=getNumberOfCells();
1926   static const int possibleCompType[]={0,1,2};
1927   if(std::find(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),compType)==possibleCompType+sizeof(possibleCompType)/sizeof(int))
1928     {
1929       std::ostringstream oss; oss << "MEDCouplingUMesh::areCellsIncludedIn : only following policies are possible : ";
1930       std::copy(possibleCompType,possibleCompType+sizeof(possibleCompType)/sizeof(int),std::ostream_iterator<int>(oss," "));
1931       oss << " !";
1932       throw INTERP_KERNEL::Exception(oss.str().c_str());
1933     }
1934   MCAuto<DataArrayInt> o2n=mesh->zipConnectivityTraducer(compType,nbOfCells);
1935   arr=o2n->subArray(nbOfCells);
1936   arr->setName(other->getName());
1937   int tmp;
1938   if(other->getNumberOfCells()==0)
1939     return true;
1940   return arr->getMaxValue(tmp)<nbOfCells;
1941 }
1942
1943 /*!
1944  * This method makes the assumption that \a this and \a other share the same coords. If not an exception will be thrown !
1945  * This method tries to determine if \b other is fully included in \b this.
1946  * The main difference is that this method is not expected to throw exception.
1947  * This method has two outputs :
1948  *
1949  * \param other other mesh
1950  * \param arr is an output parameter that returns a \b newly created instance. This array is of size 'other->getNumberOfCells()'.
1951  * \return If \a other is fully included in 'this 'true is returned. If not false is returned.
1952  */
1953 bool MEDCouplingUMesh::areCellsIncludedInPolicy7(const MEDCouplingUMesh *other, DataArrayInt *& arr) const
1954 {
1955   MCAuto<MEDCouplingUMesh> mesh=MergeUMeshesOnSameCoords(this,other);
1956   DataArrayInt *commonCells=0,*commonCellsI=0;
1957   int thisNbCells=getNumberOfCells();
1958   mesh->findCommonCells(7,thisNbCells,commonCells,commonCellsI);
1959   MCAuto<DataArrayInt> commonCellsTmp(commonCells),commonCellsITmp(commonCellsI);
1960   const int *commonCellsPtr=commonCells->getConstPointer(),*commonCellsIPtr=commonCellsI->getConstPointer();
1961   int otherNbCells=other->getNumberOfCells();
1962   MCAuto<DataArrayInt> arr2=DataArrayInt::New();
1963   arr2->alloc(otherNbCells,1);
1964   arr2->fillWithZero();
1965   int *arr2Ptr=arr2->getPointer();
1966   int nbOfCommon=commonCellsI->getNumberOfTuples()-1;
1967   for(int i=0;i<nbOfCommon;i++)
1968     {
1969       int start=commonCellsPtr[commonCellsIPtr[i]];
1970       if(start<thisNbCells)
1971         {
1972           for(int j=commonCellsIPtr[i]+1;j!=commonCellsIPtr[i+1];j++)
1973             {
1974               int sig=commonCellsPtr[j]>0?1:-1;
1975               int val=std::abs(commonCellsPtr[j])-1;
1976               if(val>=thisNbCells)
1977                 arr2Ptr[val-thisNbCells]=sig*(start+1);
1978             }
1979         }
1980     }
1981   arr2->setName(other->getName());
1982   if(arr2->presenceOfValue(0))
1983     return false;
1984   arr=arr2.retn();
1985   return true;
1986 }
1987
1988 MEDCouplingUMesh *MEDCouplingUMesh::mergeMyselfWithOnSameCoords(const MEDCouplingPointSet *other) const
1989 {
1990   if(!other)
1991     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : input other is null !");
1992   const MEDCouplingUMesh *otherC=dynamic_cast<const MEDCouplingUMesh *>(other);
1993   if(!otherC)
1994     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::mergeMyselfWithOnSameCoords : the input other mesh is not of type unstructured !");
1995   std::vector<const MEDCouplingUMesh *> ms(2);
1996   ms[0]=this;
1997   ms[1]=otherC;
1998   return MergeUMeshesOnSameCoords(ms);
1999 }
2000
2001 /*!
2002  * Build a sub part of \b this lying or not on the same coordinates than \b this (regarding value of \b keepCoords).
2003  * By default coordinates are kept. This method is close to MEDCouplingUMesh::buildPartOfMySelf except that here input
2004  * cellIds is not given explicitely but by a range python like.
2005  * 
2006  * \param start
2007  * \param end
2008  * \param step
2009  * \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.
2010  * \return a newly allocated
2011  * 
2012  * \warning This method modifies can generate an unstructured mesh whose cells are not sorted by geometric type order.
2013  * In view of the MED file writing, a renumbering of cells of returned unstructured mesh (using MEDCouplingUMesh::sortCellsInMEDFileFrmt) should be necessary.
2014  */
2015 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfSlice(int start, int end, int step, bool keepCoords) const
2016 {
2017   if(getMeshDimension()!=-1)
2018     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelfSlice(start,end,step,keepCoords));
2019   else
2020     {
2021       int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfSlice for -1 dimension mesh ");
2022       if(newNbOfCells!=1)
2023         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2024       if(start!=0)
2025         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2026       incrRef();
2027       return const_cast<MEDCouplingUMesh *>(this);
2028     }
2029 }
2030
2031 /*!
2032  * Creates a new MEDCouplingUMesh containing specified cells of \a this mesh.
2033  * The result mesh shares or not the node coordinates array with \a this mesh depending
2034  * on \a keepCoords parameter.
2035  *  \warning Cells of the result mesh can be \b not sorted by geometric type, hence,
2036  *           to write this mesh to the MED file, its cells must be sorted using
2037  *           sortCellsInMEDFileFrmt().
2038  *  \param [in] begin - an array of cell ids to include to the new mesh.
2039  *  \param [in] end - a pointer to last-plus-one-th element of \a begin.
2040  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2041  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2042  *         by calling zipCoords().
2043  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2044  *         to delete this mesh using decrRef() as it is no more needed. 
2045  *  \throw If the coordinates array is not set.
2046  *  \throw If the nodal connectivity of cells is not defined.
2047  *  \throw If any cell id in the array \a begin is not valid.
2048  *
2049  *  \if ENABLE_EXAMPLES
2050  *  \ref cpp_mcumesh_buildPartOfMySelf "Here is a C++ example".<br>
2051  *  \ref  py_mcumesh_buildPartOfMySelf "Here is a Python example".
2052  *  \endif
2053  */
2054 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelf(const int *begin, const int *end, bool keepCoords) const
2055 {
2056   if(getMeshDimension()!=-1)
2057     return static_cast<MEDCouplingUMesh *>(MEDCouplingPointSet::buildPartOfMySelf(begin,end,keepCoords));
2058   else
2059     {
2060       if(end-begin!=1)
2061         throw INTERP_KERNEL::Exception("-1D mesh has only one cell !");
2062       if(begin[0]!=0)
2063         throw INTERP_KERNEL::Exception("-1D mesh has only one cell : 0 !");
2064       incrRef();
2065       return const_cast<MEDCouplingUMesh *>(this);
2066     }
2067 }
2068
2069 /*!
2070  * This method operates only on nodal connectivity on \b this. Coordinates of \b this is completely ignored here.
2071  *
2072  * 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.
2073  * Size of [ \b cellIdsBg, \b cellIdsEnd ) ) must be equal to the number of cells of otherOnSameCoordsThanThis.
2074  * The number of cells of \b this will remain the same with this method.
2075  *
2076  * \param [in] cellIdsBg begin of cell ids (included) of cells in this to assign
2077  * \param [in] cellIdsEnd end of cell ids (excluded) of cells in this to assign
2078  * \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 ).
2079  *             Coordinate pointer of \b this and those of \b otherOnSameCoordsThanThis must be the same
2080  */
2081 void MEDCouplingUMesh::setPartOfMySelf(const int *cellIdsBg, const int *cellIdsEnd, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2082 {
2083   checkConnectivityFullyDefined();
2084   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2085   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2086     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelf : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2087   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2088     {
2089       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2090       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2091       throw INTERP_KERNEL::Exception(oss.str().c_str());
2092     }
2093   int nbOfCellsToModify=(int)std::distance(cellIdsBg,cellIdsEnd);
2094   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2095     {
2096       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2097       throw INTERP_KERNEL::Exception(oss.str().c_str());
2098     }
2099   int nbOfCells=getNumberOfCells();
2100   bool easyAssign=true;
2101   const int *connI=_nodal_connec_index->getConstPointer();
2102   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2103   for(const int *it=cellIdsBg;it!=cellIdsEnd && easyAssign;it++,connIOther++)
2104     {
2105       if(*it>=0 && *it<nbOfCells)
2106         {
2107           easyAssign=(connIOther[1]-connIOther[0])==(connI[*it+1]-connI[*it]);
2108         }
2109       else
2110         {
2111           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelf : On pos #" << std::distance(cellIdsBg,it) << " id is equal to " << *it << " which is not in [0," << nbOfCells << ") !";
2112           throw INTERP_KERNEL::Exception(oss.str().c_str());
2113         }
2114     }
2115   if(easyAssign)
2116     {
2117       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2118       computeTypes();
2119     }
2120   else
2121     {
2122       DataArrayInt *arrOut=0,*arrIOut=0;
2123       MEDCouplingUMesh::SetPartOfIndexedArrays(cellIdsBg,cellIdsEnd,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2124                                                arrOut,arrIOut);
2125       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2126       setConnectivity(arrOut,arrIOut,true);
2127     }
2128 }
2129
2130 void MEDCouplingUMesh::setPartOfMySelfSlice(int start, int end, int step, const MEDCouplingUMesh& otherOnSameCoordsThanThis)
2131 {
2132   checkConnectivityFullyDefined();
2133   otherOnSameCoordsThanThis.checkConnectivityFullyDefined();
2134   if(getCoords()!=otherOnSameCoordsThanThis.getCoords())
2135     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::setPartOfMySelfSlice : coordinates pointer are not the same ! Invoke setCoords or call tryToShareSameCoords method !");
2136   if(getMeshDimension()!=otherOnSameCoordsThanThis.getMeshDimension())
2137     {
2138       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : Mismatch of meshdimensions ! this is equal to " << getMeshDimension();
2139       oss << ", whereas other mesh dimension is set equal to " << otherOnSameCoordsThanThis.getMeshDimension() << " !";
2140       throw INTERP_KERNEL::Exception(oss.str().c_str());
2141     }
2142   int nbOfCellsToModify=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::setPartOfMySelfSlice : ");
2143   if(nbOfCellsToModify!=otherOnSameCoordsThanThis.getNumberOfCells())
2144     {
2145       std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : cells ids length (" <<  nbOfCellsToModify << ") do not match the number of cells of other mesh (" << otherOnSameCoordsThanThis.getNumberOfCells() << ") !";
2146       throw INTERP_KERNEL::Exception(oss.str().c_str());
2147     }
2148   int nbOfCells=getNumberOfCells();
2149   bool easyAssign=true;
2150   const int *connI=_nodal_connec_index->getConstPointer();
2151   const int *connIOther=otherOnSameCoordsThanThis._nodal_connec_index->getConstPointer();
2152   int it=start;
2153   for(int i=0;i<nbOfCellsToModify && easyAssign;i++,it+=step,connIOther++)
2154     {
2155       if(it>=0 && it<nbOfCells)
2156         {
2157           easyAssign=(connIOther[1]-connIOther[0])==(connI[it+1]-connI[it]);
2158         }
2159       else
2160         {
2161           std::ostringstream oss; oss << "MEDCouplingUMesh::setPartOfMySelfSlice : On pos #" << i << " id is equal to " << it << " which is not in [0," << nbOfCells << ") !";
2162           throw INTERP_KERNEL::Exception(oss.str().c_str());
2163         }
2164     }
2165   if(easyAssign)
2166     {
2167       MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index);
2168       computeTypes();
2169     }
2170   else
2171     {
2172       DataArrayInt *arrOut=0,*arrIOut=0;
2173       MEDCouplingUMesh::SetPartOfIndexedArraysSlice(start,end,step,_nodal_connec,_nodal_connec_index,otherOnSameCoordsThanThis._nodal_connec,otherOnSameCoordsThanThis._nodal_connec_index,
2174                                                 arrOut,arrIOut);
2175       MCAuto<DataArrayInt> arrOutAuto(arrOut),arrIOutAuto(arrIOut);
2176       setConnectivity(arrOut,arrIOut,true);
2177     }
2178 }                      
2179
2180 /*!
2181  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
2182  * The resulting cell ids are stored at the end of the 'cellIdsKept' parameter.
2183  * Parameter \a fullyIn specifies if a cell that has part of its nodes in ids array is kept or not.
2184  * If \a fullyIn is true only cells whose ids are \b fully contained in [ \a begin,\a end ) tab will be kept.
2185  *
2186  * \param [in] begin input start of array of node ids.
2187  * \param [in] end input end of array of node ids.
2188  * \param [in] fullyIn input that specifies if all node ids must be in [ \a begin,\a end ) array to consider cell to be in.
2189  * \param [in,out] cellIdsKeptArr array where all candidate cell ids are put at the end.
2190  */
2191 void MEDCouplingUMesh::fillCellIdsToKeepFromNodeIds(const int *begin, const int *end, bool fullyIn, DataArrayInt *&cellIdsKeptArr) const
2192 {
2193   MCAuto<DataArrayInt> cellIdsKept=DataArrayInt::New(); cellIdsKept->alloc(0,1);
2194   checkConnectivityFullyDefined();
2195   int tmp=-1;
2196   int sz=getNodalConnectivity()->getMaxValue(tmp); sz=std::max(sz,0)+1;
2197   std::vector<bool> fastFinder(sz,false);
2198   for(const int *work=begin;work!=end;work++)
2199     if(*work>=0 && *work<sz)
2200       fastFinder[*work]=true;
2201   int nbOfCells=getNumberOfCells();
2202   const int *conn=getNodalConnectivity()->getConstPointer();
2203   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2204   for(int i=0;i<nbOfCells;i++)
2205     {
2206       int ref=0,nbOfHit=0;
2207       for(const int *work2=conn+connIndex[i]+1;work2!=conn+connIndex[i+1];work2++)
2208         if(*work2>=0)
2209           {
2210             ref++;
2211             if(fastFinder[*work2])
2212               nbOfHit++;
2213           }
2214       if((ref==nbOfHit && fullyIn) || (nbOfHit!=0 && !fullyIn))
2215         cellIdsKept->pushBackSilent(i);
2216     }
2217   cellIdsKeptArr=cellIdsKept.retn();
2218 }
2219
2220 /*!
2221  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2222  * this->getMeshDimension(), that bound some cells of \a this mesh.
2223  * The cells of lower dimension to include to the result mesh are selected basing on
2224  * specified node ids and the value of \a fullyIn parameter. If \a fullyIn ==\c true, a
2225  * cell is copied if its all nodes are in the array \a begin of node ids. If \a fullyIn
2226  * ==\c false, a cell is copied if any its node is in the array of node ids. The
2227  * created mesh shares the node coordinates array with \a this mesh. 
2228  *  \param [in] begin - the array of node ids.
2229  *  \param [in] end - a pointer to the (last+1)-th element of \a begin.
2230  *  \param [in] fullyIn - if \c true, then cells whose all nodes are in the
2231  *         array \a begin are added, else cells whose any node is in the
2232  *         array \a begin are added.
2233  *  \return MEDCouplingUMesh * - new instance of MEDCouplingUMesh. The caller is
2234  *         to delete this mesh using decrRef() as it is no more needed. 
2235  *  \throw If the coordinates array is not set.
2236  *  \throw If the nodal connectivity of cells is not defined.
2237  *  \throw If any node id in \a begin is not valid.
2238  *
2239  *  \if ENABLE_EXAMPLES
2240  *  \ref cpp_mcumesh_buildFacePartOfMySelfNode "Here is a C++ example".<br>
2241  *  \ref  py_mcumesh_buildFacePartOfMySelfNode "Here is a Python example".
2242  *  \endif
2243  */
2244 MEDCouplingUMesh *MEDCouplingUMesh::buildFacePartOfMySelfNode(const int *begin, const int *end, bool fullyIn) const
2245 {
2246   MCAuto<DataArrayInt> desc,descIndx,revDesc,revDescIndx;
2247   desc=DataArrayInt::New(); descIndx=DataArrayInt::New(); revDesc=DataArrayInt::New(); revDescIndx=DataArrayInt::New();
2248   MCAuto<MEDCouplingUMesh> subMesh=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2249   desc=0; descIndx=0; revDesc=0; revDescIndx=0;
2250   return static_cast<MEDCouplingUMesh*>(subMesh->buildPartOfMySelfNode(begin,end,fullyIn));
2251 }
2252
2253 /*!
2254  * Creates a new MEDCouplingUMesh containing cells, of dimension one less than \a
2255  * this->getMeshDimension(), which bound only one cell of \a this mesh.
2256  *  \param [in] keepCoords - if \c true, the result mesh shares the node coordinates
2257  *         array of \a this mesh, else "free" nodes are removed from the result mesh
2258  *         by calling zipCoords().
2259  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. The caller is
2260  *         to delete this mesh using decrRef() as it is no more needed. 
2261  *  \throw If the coordinates array is not set.
2262  *  \throw If the nodal connectivity of cells is not defined.
2263  *
2264  *  \if ENABLE_EXAMPLES
2265  *  \ref cpp_mcumesh_buildBoundaryMesh "Here is a C++ example".<br>
2266  *  \ref  py_mcumesh_buildBoundaryMesh "Here is a Python example".
2267  *  \endif
2268  */
2269 MEDCouplingUMesh *MEDCouplingUMesh::buildBoundaryMesh(bool keepCoords) const
2270 {
2271   DataArrayInt *desc=DataArrayInt::New();
2272   DataArrayInt *descIndx=DataArrayInt::New();
2273   DataArrayInt *revDesc=DataArrayInt::New();
2274   DataArrayInt *revDescIndx=DataArrayInt::New();
2275   //
2276   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2277   revDesc->decrRef();
2278   desc->decrRef();
2279   descIndx->decrRef();
2280   int nbOfCells=meshDM1->getNumberOfCells();
2281   const int *revDescIndxC=revDescIndx->getConstPointer();
2282   std::vector<int> boundaryCells;
2283   for(int i=0;i<nbOfCells;i++)
2284     if(revDescIndxC[i+1]-revDescIndxC[i]==1)
2285       boundaryCells.push_back(i);
2286   revDescIndx->decrRef();
2287   MEDCouplingUMesh *ret=meshDM1->buildPartOfMySelf(&boundaryCells[0],&boundaryCells[0]+boundaryCells.size(),keepCoords);
2288   return ret;
2289 }
2290
2291 /*!
2292  * This method returns a newly created DataArrayInt instance containing ids of cells located in boundary.
2293  * A cell is detected to be on boundary if it contains one or more than one face having only one father.
2294  * This method makes the assumption that \a this is fully defined (coords,connectivity). If not an exception will be thrown. 
2295  */
2296 DataArrayInt *MEDCouplingUMesh::findCellIdsOnBoundary() const
2297 {
2298   checkFullyDefined();
2299   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2300   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2301   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2302   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2303   //
2304   buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx)->decrRef();
2305   desc=(DataArrayInt*)0; descIndx=(DataArrayInt*)0;
2306   //
2307   MCAuto<DataArrayInt> tmp=revDescIndx->deltaShiftIndex();
2308   MCAuto<DataArrayInt> faceIds=tmp->findIdsEqual(1); tmp=(DataArrayInt*)0;
2309   const int *revDescPtr=revDesc->getConstPointer();
2310   const int *revDescIndxPtr=revDescIndx->getConstPointer();
2311   int nbOfCells=getNumberOfCells();
2312   std::vector<bool> ret1(nbOfCells,false);
2313   int sz=0;
2314   for(const int *pt=faceIds->begin();pt!=faceIds->end();pt++)
2315     if(!ret1[revDescPtr[revDescIndxPtr[*pt]]])
2316       { ret1[revDescPtr[revDescIndxPtr[*pt]]]=true; sz++; }
2317   //
2318   DataArrayInt *ret2=DataArrayInt::New();
2319   ret2->alloc(sz,1);
2320   int *ret2Ptr=ret2->getPointer();
2321   sz=0;
2322   for(std::vector<bool>::const_iterator it=ret1.begin();it!=ret1.end();it++,sz++)
2323     if(*it)
2324       *ret2Ptr++=sz;
2325   ret2->setName("BoundaryCells");
2326   return ret2;
2327 }
2328
2329 /*!
2330  * This method finds in \b this the cell ids that lie on mesh \b otherDimM1OnSameCoords.
2331  * \b this and \b otherDimM1OnSameCoords have to lie on the same coordinate array pointer. The coherency of that coords array with connectivity
2332  * of \b this and \b otherDimM1OnSameCoords is not important here because this method works only on connectivity.
2333  * this->getMeshDimension() - 1 must be equal to otherDimM1OnSameCoords.getMeshDimension()
2334  *
2335  * s0 is the cell ids set in \b this lying on at least one node in the fetched nodes in \b otherDimM1OnSameCoords.
2336  * 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
2337  * equals a cell in \b otherDimM1OnSameCoords.
2338  *
2339  * \throw if \b otherDimM1OnSameCoords is not part of constituent of \b this, or if coordinate pointer of \b this and \b otherDimM1OnSameCoords
2340  *        are not same, or if this->getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension()
2341  *
2342  * \param [in] otherDimM1OnSameCoords
2343  * \param [out] cellIdsRk0 a newly allocated array containing the cell ids of s0 (which are cell ids of \b this) in the above algorithm.
2344  * \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
2345  *              cellIdsRk1->transformWithIndArr(cellIdsRk0->begin(),cellIdsRk0->end());
2346  */
2347 void MEDCouplingUMesh::findCellIdsLyingOn(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *&cellIdsRk0, DataArrayInt *&cellIdsRk1) const
2348 {
2349   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2350     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : coordinates pointer are not the same ! Use tryToShareSameCoords method !");
2351   checkConnectivityFullyDefined();
2352   otherDimM1OnSameCoords.checkConnectivityFullyDefined();
2353   if(getMeshDimension()-1!=otherDimM1OnSameCoords.getMeshDimension())
2354     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : invalid mesh dimension of input mesh regarding meshdimesion of this !");
2355   MCAuto<DataArrayInt> fetchedNodeIds1=otherDimM1OnSameCoords.computeFetchedNodeIds();
2356   MCAuto<DataArrayInt> s0arr=getCellIdsLyingOnNodes(fetchedNodeIds1->begin(),fetchedNodeIds1->end(),false);
2357   MCAuto<MEDCouplingUMesh> thisPart=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(s0arr->begin(),s0arr->end(),true));
2358   MCAuto<DataArrayInt> descThisPart=DataArrayInt::New(),descIThisPart=DataArrayInt::New(),revDescThisPart=DataArrayInt::New(),revDescIThisPart=DataArrayInt::New();
2359   MCAuto<MEDCouplingUMesh> thisPartConsti=thisPart->buildDescendingConnectivity(descThisPart,descIThisPart,revDescThisPart,revDescIThisPart);
2360   const int *revDescThisPartPtr=revDescThisPart->getConstPointer(),*revDescIThisPartPtr=revDescIThisPart->getConstPointer();
2361   DataArrayInt *idsOtherInConsti=0;
2362   bool b=thisPartConsti->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsOtherInConsti);
2363   MCAuto<DataArrayInt> idsOtherInConstiAuto(idsOtherInConsti);
2364   if(!b)
2365     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findCellIdsLyingOn : the given mdim-1 mesh in other is not a constituent of this !");
2366   std::set<int> s1;
2367   for(const int *idOther=idsOtherInConsti->begin();idOther!=idsOtherInConsti->end();idOther++)
2368     s1.insert(revDescThisPartPtr+revDescIThisPartPtr[*idOther],revDescThisPartPtr+revDescIThisPartPtr[*idOther+1]);
2369   MCAuto<DataArrayInt> s1arr_renum1=DataArrayInt::New(); s1arr_renum1->alloc((int)s1.size(),1); std::copy(s1.begin(),s1.end(),s1arr_renum1->getPointer());
2370   s1arr_renum1->sort();
2371   cellIdsRk0=s0arr.retn();
2372   //cellIdsRk1=s_renum1.retn();
2373   cellIdsRk1=s1arr_renum1.retn();
2374 }
2375
2376 /*!
2377  * 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
2378  * returned. This subpart of meshdim-1 mesh is built using meshdim-1 cells in it shared only one cell in \b this.
2379  * 
2380  * \return a newly allocated mesh lying on the same coordinates than \b this. The caller has to deal with returned mesh.
2381  */
2382 MEDCouplingUMesh *MEDCouplingUMesh::computeSkin() const
2383 {
2384   MCAuto<DataArrayInt> desc=DataArrayInt::New();
2385   MCAuto<DataArrayInt> descIndx=DataArrayInt::New();
2386   MCAuto<DataArrayInt> revDesc=DataArrayInt::New();
2387   MCAuto<DataArrayInt> revDescIndx=DataArrayInt::New();
2388   //
2389   MCAuto<MEDCouplingUMesh> meshDM1=buildDescendingConnectivity(desc,descIndx,revDesc,revDescIndx);
2390   revDesc=0; desc=0; descIndx=0;
2391   MCAuto<DataArrayInt> revDescIndx2=revDescIndx->deltaShiftIndex();
2392   MCAuto<DataArrayInt> part=revDescIndx2->findIdsEqual(1);
2393   return static_cast<MEDCouplingUMesh *>(meshDM1->buildPartOfMySelf(part->begin(),part->end(),true));
2394 }
2395
2396 /*!
2397  * Finds nodes lying on the boundary of \a this mesh.
2398  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of found
2399  *          nodes. The caller is to delete this array using decrRef() as it is no
2400  *          more needed.
2401  *  \throw If the coordinates array is not set.
2402  *  \throw If the nodal connectivity of cells is node defined.
2403  *
2404  *  \if ENABLE_EXAMPLES
2405  *  \ref cpp_mcumesh_findBoundaryNodes "Here is a C++ example".<br>
2406  *  \ref  py_mcumesh_findBoundaryNodes "Here is a Python example".
2407  *  \endif
2408  */
2409 DataArrayInt *MEDCouplingUMesh::findBoundaryNodes() const
2410 {
2411   MCAuto<MEDCouplingUMesh> skin=computeSkin();
2412   return skin->computeFetchedNodeIds();
2413 }
2414
2415 MEDCouplingUMesh *MEDCouplingUMesh::buildUnstructured() const
2416 {
2417   incrRef();
2418   return const_cast<MEDCouplingUMesh *>(this);
2419 }
2420
2421 /*!
2422  * This method expects that \b this and \b otherDimM1OnSameCoords share the same coordinates array.
2423  * otherDimM1OnSameCoords->getMeshDimension() is expected to be equal to this->getMeshDimension()-1.
2424  * 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.
2425  * 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.
2426  * 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.
2427  *
2428  * \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
2429  *             parameter is altered during the call.
2430  * \param [out] nodeIdsToDuplicate node ids needed to be duplicated following the algorithm explain above.
2431  * \param [out] cellIdsNeededToBeRenum cell ids in \b this in which the renumber of nodes should be performed.
2432  * \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.
2433  *
2434  * \warning This method modifies param \b otherDimM1OnSameCoords (for speed reasons).
2435  */
2436 void MEDCouplingUMesh::findNodesToDuplicate(const MEDCouplingUMesh& otherDimM1OnSameCoords, DataArrayInt *& nodeIdsToDuplicate,
2437                                             DataArrayInt *& cellIdsNeededToBeRenum, DataArrayInt *& cellIdsNotModified) const
2438 {
2439   typedef MCAuto<DataArrayInt> DAInt;
2440   typedef MCAuto<MEDCouplingUMesh> MCUMesh;
2441
2442   checkFullyDefined();
2443   otherDimM1OnSameCoords.checkFullyDefined();
2444   if(getCoords()!=otherDimM1OnSameCoords.getCoords())
2445     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : meshes do not share the same coords array !");
2446   if(otherDimM1OnSameCoords.getMeshDimension()!=getMeshDimension()-1)
2447     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate : the mesh given in other parameter must have this->getMeshDimension()-1 !");
2448
2449   // Checking star-shaped M1 group:
2450   DAInt dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2451   MCUMesh meshM2 = otherDimM1OnSameCoords.buildDescendingConnectivity(dt0, dit0, rdt0, rdit0);
2452   DAInt dsi = rdit0->deltaShiftIndex();
2453   DAInt idsTmp0 = dsi->findIdsNotInRange(-1, 3);
2454   if(idsTmp0->getNumberOfTuples())
2455     throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group: group is too complex: some points (or edges) have more than two connected segments (or faces)!");
2456   dt0=0; dit0=0; rdt0=0; rdit0=0; idsTmp0=0;
2457
2458   // Get extreme nodes from the group (they won't be duplicated), ie nodes belonging to boundary cells of M1
2459   DAInt xtremIdsM2 = dsi->findIdsEqual(1); dsi = 0;
2460   MCUMesh meshM2Part = static_cast<MEDCouplingUMesh *>(meshM2->buildPartOfMySelf(xtremIdsM2->begin(), xtremIdsM2->end(),true));
2461   DAInt xtrem = meshM2Part->computeFetchedNodeIds();
2462   // Remove from the list points on the boundary of the M0 mesh (those need duplication!)
2463   dt0=DataArrayInt::New(),dit0=DataArrayInt::New(),rdt0=DataArrayInt::New(),rdit0=DataArrayInt::New();
2464   MCUMesh m0desc = buildDescendingConnectivity(dt0, dit0, rdt0, rdit0); dt0=0; dit0=0; rdt0=0;
2465   dsi = rdit0->deltaShiftIndex();
2466   DAInt boundSegs = dsi->findIdsEqual(1);   // boundary segs/faces of the M0 mesh
2467   MCUMesh m0descSkin = static_cast<MEDCouplingUMesh *>(m0desc->buildPartOfMySelf(boundSegs->begin(),boundSegs->end(), true));
2468   DAInt fNodes = m0descSkin->computeFetchedNodeIds();
2469   // In 3D, some points on the boundary of M0 still need duplication:
2470   DAInt notDup = 0;
2471   if (getMeshDimension() == 3)
2472     {
2473       DAInt dnu1=DataArrayInt::New(), dnu2=DataArrayInt::New(), dnu3=DataArrayInt::New(), dnu4=DataArrayInt::New();
2474       MCUMesh m0descSkinDesc = m0descSkin->buildDescendingConnectivity(dnu1, dnu2, dnu3, dnu4);
2475       dnu1=0;dnu2=0;dnu3=0;dnu4=0;
2476       DataArrayInt * corresp=0;
2477       meshM2->areCellsIncludedIn(m0descSkinDesc,2,corresp);
2478       DAInt validIds = corresp->findIdsInRange(0, meshM2->getNumberOfCells());
2479       corresp->decrRef();
2480       if (validIds->getNumberOfTuples())
2481         {
2482           MCUMesh m1IntersecSkin = static_cast<MEDCouplingUMesh *>(m0descSkinDesc->buildPartOfMySelf(validIds->begin(), validIds->end(), true));
2483           DAInt notDuplSkin = m1IntersecSkin->findBoundaryNodes();
2484           DAInt fNodes1 = fNodes->buildSubstraction(notDuplSkin);
2485           notDup = xtrem->buildSubstraction(fNodes1);
2486         }
2487       else
2488         notDup = xtrem->buildSubstraction(fNodes);
2489     }
2490   else
2491     notDup = xtrem->buildSubstraction(fNodes);
2492
2493   // Now compute cells around group (i.e. cells where we will do the propagation to identify the two sub-sets delimited by the group)
2494   DAInt m1Nodes = otherDimM1OnSameCoords.computeFetchedNodeIds();
2495   DAInt dupl = m1Nodes->buildSubstraction(notDup);
2496   DAInt cellsAroundGroup = getCellIdsLyingOnNodes(dupl->begin(), dupl->end(), false);  // false= take cell in, even if not all nodes are in notDup
2497
2498   //
2499   MCUMesh m0Part2=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(cellsAroundGroup->begin(),cellsAroundGroup->end(),true));
2500   int nCells2 = m0Part2->getNumberOfCells();
2501   DAInt desc00=DataArrayInt::New(),descI00=DataArrayInt::New(),revDesc00=DataArrayInt::New(),revDescI00=DataArrayInt::New();
2502   MCUMesh m01=m0Part2->buildDescendingConnectivity(desc00,descI00,revDesc00,revDescI00);
2503
2504   // Neighbor information of the mesh without considering the crack (serves to count how many connex pieces it is made of)
2505   DataArrayInt *tmp00=0,*tmp11=0;
2506   MEDCouplingUMesh::ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00, tmp00, tmp11);
2507   DAInt neighInit00(tmp00);
2508   DAInt neighIInit00(tmp11);
2509   // Neighbor information of the mesh WITH the crack (some neighbors are removed):
2510   DataArrayInt *idsTmp=0;
2511   bool b=m01->areCellsIncludedIn(&otherDimM1OnSameCoords,2,idsTmp);
2512   DAInt ids(idsTmp);
2513   // In the neighbor information remove the connection between high dimension cells and its low level constituents which are part
2514   // of the frontier given in parameter (i.e. the cells of low dimension from the group delimiting the crack):
2515   MEDCouplingUMesh::RemoveIdsFromIndexedArrays(ids->begin(),ids->end(),desc00,descI00);
2516   DataArrayInt *tmp0=0,*tmp1=0;
2517   // Compute the neighbor of each cell in m0Part2, taking into account the broken link above. Two
2518   // cells on either side of the crack (defined by the mesh of low dimension) are not neighbor anymore.
2519   ComputeNeighborsOfCellsAdv(desc00,descI00,revDesc00,revDescI00,tmp0,tmp1);
2520   DAInt neigh00(tmp0);
2521   DAInt neighI00(tmp1);
2522
2523   // For each initial connex part of the sub-mesh (or said differently for each independent crack):
2524   int seed = 0, nIter = 0;
2525   int nIterMax = nCells2+1; // Safety net for the loop
2526   DAInt hitCells = DataArrayInt::New(); hitCells->alloc(nCells2);
2527   hitCells->fillWithValue(-1);
2528   DAInt cellsToModifyConn0_torenum = DataArrayInt::New();
2529   cellsToModifyConn0_torenum->alloc(0,1);
2530   while (nIter < nIterMax)
2531     {
2532       DAInt t = hitCells->findIdsEqual(-1);
2533       if (!t->getNumberOfTuples())
2534         break;
2535       // Connex zone without the crack (to compute the next seed really)
2536       int dnu;
2537       DAInt connexCheck = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neighInit00,neighIInit00, -1, dnu);
2538       int cnt = 0;
2539       for (int * ptr = connexCheck->getPointer(); cnt < connexCheck->getNumberOfTuples(); ptr++, cnt++)
2540         hitCells->setIJ(*ptr,0,1);
2541       // Connex zone WITH the crack (to identify cells lying on either part of the crack)
2542       DAInt spreadZone = MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(&seed, &seed+1, neigh00,neighI00, -1, dnu);
2543       cellsToModifyConn0_torenum = DataArrayInt::Aggregate(cellsToModifyConn0_torenum, spreadZone, 0);
2544       // Compute next seed, i.e. a cell in another connex part, which was not covered by the previous iterations
2545       DAInt comple = cellsToModifyConn0_torenum->buildComplement(nCells2);
2546       DAInt nonHitCells = hitCells->findIdsEqual(-1);
2547       DAInt intersec = nonHitCells->buildIntersection(comple);
2548       if (intersec->getNumberOfTuples())
2549         { seed = intersec->getIJ(0,0); }
2550       else
2551         { break; }
2552       nIter++;
2553     }
2554   if (nIter >= nIterMax)
2555     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::findNodesToDuplicate(): internal error - too many iterations.");
2556
2557   DAInt cellsToModifyConn1_torenum=cellsToModifyConn0_torenum->buildComplement(neighI00->getNumberOfTuples()-1);
2558   cellsToModifyConn0_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2559   cellsToModifyConn1_torenum->transformWithIndArr(cellsAroundGroup->begin(),cellsAroundGroup->end());
2560   //
2561   cellIdsNeededToBeRenum=cellsToModifyConn0_torenum.retn();
2562   cellIdsNotModified=cellsToModifyConn1_torenum.retn();
2563   nodeIdsToDuplicate=dupl.retn();
2564 }
2565
2566 /*!
2567  * This method operates a modification of the connectivity and coords in \b this.
2568  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2569  * its ids will be modified to id this->getNumberOfNodes()+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2570  * 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
2571  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id this->getNumberOfNodes()+0, node id nodeIdsToDuplicateBg[1] will have id this->getNumberOfNodes()+1,
2572  * node id nodeIdsToDuplicateBg[2] will have id this->getNumberOfNodes()+2...
2573  * 
2574  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2575  * 
2576  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2577  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2578  */
2579 void MEDCouplingUMesh::duplicateNodes(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd)
2580 {
2581   int nbOfNodes=getNumberOfNodes();
2582   duplicateNodesInCoords(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd);
2583   duplicateNodesInConn(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,nbOfNodes);
2584 }
2585
2586 /*!
2587  * This method renumbers only nodal connectivity in \a this. The renumbering is only an offset applied. So this method is a specialization of
2588  * \a renumberNodesInConn. \b WARNING, this method does not check that the resulting node ids in the nodal connectivity is in a valid range !
2589  *
2590  * \param [in] offset - specifies the offset to be applied on each element of connectivity.
2591  *
2592  * \sa renumberNodesInConn
2593  */
2594 void MEDCouplingUMesh::renumberNodesWithOffsetInConn(int offset)
2595 {
2596   checkConnectivityFullyDefined();
2597   int *conn(getNodalConnectivity()->getPointer());
2598   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2599   int nbOfCells(getNumberOfCells());
2600   for(int i=0;i<nbOfCells;i++)
2601     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2602       {
2603         int& node=conn[iconn];
2604         if(node>=0)//avoid polyhedron separator
2605           {
2606             node+=offset;
2607           }
2608       }
2609   _nodal_connec->declareAsNew();
2610   updateTime();
2611 }
2612
2613 /*!
2614  *  Same than renumberNodesInConn(const int *) except that here the format of old-to-new traducer is using map instead
2615  *  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
2616  *  of a big mesh.
2617  */
2618 void MEDCouplingUMesh::renumberNodesInConn(const INTERP_KERNEL::HashMap<int,int>& newNodeNumbersO2N)
2619 {
2620   checkConnectivityFullyDefined();
2621   int *conn(getNodalConnectivity()->getPointer());
2622   const int *connIndex(getNodalConnectivityIndex()->getConstPointer());
2623   int nbOfCells(getNumberOfCells());
2624   for(int i=0;i<nbOfCells;i++)
2625     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2626       {
2627         int& node=conn[iconn];
2628         if(node>=0)//avoid polyhedron separator
2629           {
2630             INTERP_KERNEL::HashMap<int,int>::const_iterator it(newNodeNumbersO2N.find(node));
2631             if(it!=newNodeNumbersO2N.end())
2632               {
2633                 node=(*it).second;
2634               }
2635             else
2636               {
2637                 std::ostringstream oss; oss << "MEDCouplingUMesh::renumberNodesInConn(map) : presence in connectivity for cell #" << i << " of node #" << node << " : Not in map !";
2638                 throw INTERP_KERNEL::Exception(oss.str().c_str());
2639               }
2640           }
2641       }
2642   _nodal_connec->declareAsNew();
2643   updateTime();
2644 }
2645
2646 /*!
2647  * Changes ids of nodes within the nodal connectivity arrays according to a permutation
2648  * array in "Old to New" mode. The node coordinates array is \b not changed by this method.
2649  * This method is a generalization of shiftNodeNumbersInConn().
2650  *  \warning This method performs no check of validity of new ids. **Use it with care !**
2651  *  \param [in] newNodeNumbersO2N - a permutation array, of length \a
2652  *         this->getNumberOfNodes(), in "Old to New" mode. 
2653  *         See \ref numbering for more info on renumbering modes.
2654  *  \throw If the nodal connectivity of cells is not defined.
2655  *
2656  *  \if ENABLE_EXAMPLES
2657  *  \ref cpp_mcumesh_renumberNodesInConn "Here is a C++ example".<br>
2658  *  \ref  py_mcumesh_renumberNodesInConn "Here is a Python example".
2659  *  \endif
2660  */
2661 void MEDCouplingUMesh::renumberNodesInConn(const int *newNodeNumbersO2N)
2662 {
2663   checkConnectivityFullyDefined();
2664   int *conn=getNodalConnectivity()->getPointer();
2665   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2666   int nbOfCells(getNumberOfCells());
2667   for(int i=0;i<nbOfCells;i++)
2668     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2669       {
2670         int& node=conn[iconn];
2671         if(node>=0)//avoid polyhedron separator
2672           {
2673             node=newNodeNumbersO2N[node];
2674           }
2675       }
2676   _nodal_connec->declareAsNew();
2677   updateTime();
2678 }
2679
2680 /*!
2681  * This method renumbers nodes \b in \b connectivity \b only \b without \b any \b reference \b to \b coords.
2682  * This method performs no check on the fact that new coordinate ids are valid. \b Use \b it \b with \b care !
2683  * This method is an specialization of \ref MEDCoupling::MEDCouplingUMesh::renumberNodesInConn "renumberNodesInConn method".
2684  * 
2685  * \param [in] delta specifies the shift size applied to nodeId in nodal connectivity in \b this.
2686  */
2687 void MEDCouplingUMesh::shiftNodeNumbersInConn(int delta)
2688 {
2689   checkConnectivityFullyDefined();
2690   int *conn=getNodalConnectivity()->getPointer();
2691   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2692   int nbOfCells=getNumberOfCells();
2693   for(int i=0;i<nbOfCells;i++)
2694     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2695       {
2696         int& node=conn[iconn];
2697         if(node>=0)//avoid polyhedron separator
2698           {
2699             node+=delta;
2700           }
2701       }
2702   _nodal_connec->declareAsNew();
2703   updateTime();
2704 }
2705
2706 /*!
2707  * This method operates a modification of the connectivity in \b this.
2708  * 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.
2709  * Every time that a node id in [ \b nodeIdsToDuplicateBg, \b nodeIdsToDuplicateEnd ) will append in nodal connectivity of \b this 
2710  * its ids will be modified to id offset+std::distance(nodeIdsToDuplicateBg,std::find(nodeIdsToDuplicateBg,nodeIdsToDuplicateEnd,id)).
2711  * 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
2712  * renumbered. The node id nodeIdsToDuplicateBg[0] will have id offset+0, node id nodeIdsToDuplicateBg[1] will have id offset+1,
2713  * node id nodeIdsToDuplicateBg[2] will have id offset+2...
2714  * 
2715  * As a consequence nodal connectivity array length will remain unchanged by this method, and nodal connectivity index array will remain unchanged by this method.
2716  * As an another consequense after the call of this method \b this can be transiently non cohrent.
2717  * 
2718  * \param [in] nodeIdsToDuplicateBg begin of node ids (included) to be duplicated in connectivity only
2719  * \param [in] nodeIdsToDuplicateEnd end of node ids (excluded) to be duplicated in connectivity only
2720  * \param [in] offset the offset applied to all node ids in connectivity that are in [ \a nodeIdsToDuplicateBg, \a nodeIdsToDuplicateEnd ). 
2721  */
2722 void MEDCouplingUMesh::duplicateNodesInConn(const int *nodeIdsToDuplicateBg, const int *nodeIdsToDuplicateEnd, int offset)
2723 {
2724   checkConnectivityFullyDefined();
2725   std::map<int,int> m;
2726   int val=offset;
2727   for(const int *work=nodeIdsToDuplicateBg;work!=nodeIdsToDuplicateEnd;work++,val++)
2728     m[*work]=val;
2729   int *conn=getNodalConnectivity()->getPointer();
2730   const int *connIndex=getNodalConnectivityIndex()->getConstPointer();
2731   int nbOfCells=getNumberOfCells();
2732   for(int i=0;i<nbOfCells;i++)
2733     for(int iconn=connIndex[i]+1;iconn!=connIndex[i+1];iconn++)
2734       {
2735         int& node=conn[iconn];
2736         if(node>=0)//avoid polyhedron separator
2737           {
2738             std::map<int,int>::iterator it=m.find(node);
2739             if(it!=m.end())
2740               node=(*it).second;
2741           }
2742       }
2743   updateTime();
2744 }
2745
2746 /*!
2747  * This method renumbers cells of \a this using the array specified by [old2NewBg;old2NewBg+getNumberOfCells())
2748  *
2749  * Contrary to MEDCouplingPointSet::renumberNodes, this method makes a permutation without any fuse of cell.
2750  * After the call of this method the number of cells remains the same as before.
2751  *
2752  * If 'check' equals true the method will check that any elements in [ \a old2NewBg; \a old2NewEnd ) is unique ; if not
2753  * an INTERP_KERNEL::Exception will be thrown. When 'check' equals true [ \a old2NewBg ; \a old2NewEnd ) is not expected to
2754  * be strictly in [0;this->getNumberOfCells()).
2755  *
2756  * If 'check' equals false the method will not check the content of [ \a old2NewBg ; \a old2NewEnd ).
2757  * To avoid any throw of SIGSEGV when 'check' equals false, the elements in [ \a old2NewBg ; \a old2NewEnd ) should be unique and
2758  * should be contained in[0;this->getNumberOfCells()).
2759  * 
2760  * \param [in] old2NewBg is expected to be a dynamically allocated pointer of size at least equal to this->getNumberOfCells()
2761  * \param check
2762  */
2763 void MEDCouplingUMesh::renumberCells(const int *old2NewBg, bool check)
2764 {
2765   checkConnectivityFullyDefined();
2766   int nbCells=getNumberOfCells();
2767   const int *array=old2NewBg;
2768   if(check)
2769     array=DataArrayInt::CheckAndPreparePermutation(old2NewBg,old2NewBg+nbCells);
2770   //
2771   const int *conn=_nodal_connec->getConstPointer();
2772   const int *connI=_nodal_connec_index->getConstPointer();
2773   MCAuto<DataArrayInt> o2n=DataArrayInt::New(); o2n->useArray(array,false,C_DEALLOC,nbCells,1);
2774   MCAuto<DataArrayInt> n2o=o2n->invertArrayO2N2N2O(nbCells);
2775   const int *n2oPtr=n2o->begin();
2776   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
2777   newConn->alloc(_nodal_connec->getNumberOfTuples(),_nodal_connec->getNumberOfComponents());
2778   newConn->copyStringInfoFrom(*_nodal_connec);
2779   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
2780   newConnI->alloc(_nodal_connec_index->getNumberOfTuples(),_nodal_connec_index->getNumberOfComponents());
2781   newConnI->copyStringInfoFrom(*_nodal_connec_index);
2782   //
2783   int *newC=newConn->getPointer();
2784   int *newCI=newConnI->getPointer();
2785   int loc=0;
2786   newCI[0]=loc;
2787   for(int i=0;i<nbCells;i++)
2788     {
2789       int pos=n2oPtr[i];
2790       int nbOfElts=connI[pos+1]-connI[pos];
2791       newC=std::copy(conn+connI[pos],conn+connI[pos+1],newC);
2792       loc+=nbOfElts;
2793       newCI[i+1]=loc;
2794     }
2795   //
2796   setConnectivity(newConn,newConnI);
2797   if(check)
2798     free(const_cast<int *>(array));
2799 }
2800
2801 /*!
2802  * Finds cells whose bounding boxes intersect a given bounding box.
2803  *  \param [in] bbox - an array defining the bounding box via coordinates of its
2804  *         extremum points in "no interlace" mode, i.e. xMin, xMax, yMin, yMax, zMin,
2805  *         zMax (if in 3D). 
2806  *  \param [in] eps - a factor used to increase size of the bounding box of cell
2807  *         before comparing it with \a bbox. This factor is multiplied by the maximal
2808  *         extent of the bounding box of cell to produce an addition to this bounding box.
2809  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids for found
2810  *         cells. The caller is to delete this array using decrRef() as it is no more
2811  *         needed. 
2812  *  \throw If the coordinates array is not set.
2813  *  \throw If the nodal connectivity of cells is not defined.
2814  *
2815  *  \if ENABLE_EXAMPLES
2816  *  \ref cpp_mcumesh_getCellsInBoundingBox "Here is a C++ example".<br>
2817  *  \ref  py_mcumesh_getCellsInBoundingBox "Here is a Python example".
2818  *  \endif
2819  */
2820 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const double *bbox, double eps) const
2821 {
2822   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2823   if(getMeshDimension()==-1)
2824     {
2825       elems->pushBackSilent(0);
2826       return elems.retn();
2827     }
2828   int dim=getSpaceDimension();
2829   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2830   const int* conn      = getNodalConnectivity()->getConstPointer();
2831   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2832   const double* coords = getCoords()->getConstPointer();
2833   int nbOfCells=getNumberOfCells();
2834   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2835     {
2836       for (int i=0; i<dim; i++)
2837         {
2838           elem_bb[i*2]=std::numeric_limits<double>::max();
2839           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2840         }
2841
2842       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2843         {
2844           int node= conn[inode];
2845           if(node>=0)//avoid polyhedron separator
2846             {
2847               for (int idim=0; idim<dim; idim++)
2848                 {
2849                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2850                     {
2851                       elem_bb[idim*2] = coords[node*dim+idim] ;
2852                     }
2853                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2854                     {
2855                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2856                     }
2857                 }
2858             }
2859         }
2860       if (intersectsBoundingBox(elem_bb, bbox, dim, eps))
2861         elems->pushBackSilent(ielem);
2862     }
2863   return elems.retn();
2864 }
2865
2866 /*!
2867  * Given a boundary box 'bbox' returns elements 'elems' contained in this 'bbox' or touching 'bbox' (within 'eps' distance).
2868  * Warning 'elems' is incremented during the call so if elems is not empty before call returned elements will be
2869  * added in 'elems' parameter.
2870  */
2871 DataArrayInt *MEDCouplingUMesh::getCellsInBoundingBox(const INTERP_KERNEL::DirectedBoundingBox& bbox, double eps)
2872 {
2873   MCAuto<DataArrayInt> elems=DataArrayInt::New(); elems->alloc(0,1);
2874   if(getMeshDimension()==-1)
2875     {
2876       elems->pushBackSilent(0);
2877       return elems.retn();
2878     }
2879   int dim=getSpaceDimension();
2880   INTERP_KERNEL::AutoPtr<double> elem_bb=new double[2*dim];
2881   const int* conn      = getNodalConnectivity()->getConstPointer();
2882   const int* conn_index= getNodalConnectivityIndex()->getConstPointer();
2883   const double* coords = getCoords()->getConstPointer();
2884   int nbOfCells=getNumberOfCells();
2885   for ( int ielem=0; ielem<nbOfCells;ielem++ )
2886     {
2887       for (int i=0; i<dim; i++)
2888         {
2889           elem_bb[i*2]=std::numeric_limits<double>::max();
2890           elem_bb[i*2+1]=-std::numeric_limits<double>::max();
2891         }
2892
2893       for (int inode=conn_index[ielem]+1; inode<conn_index[ielem+1]; inode++)//+1 due to offset of cell type.
2894         {
2895           int node= conn[inode];
2896           if(node>=0)//avoid polyhedron separator
2897             {
2898               for (int idim=0; idim<dim; idim++)
2899                 {
2900                   if ( coords[node*dim+idim] < elem_bb[idim*2] )
2901                     {
2902                       elem_bb[idim*2] = coords[node*dim+idim] ;
2903                     }
2904                   if ( coords[node*dim+idim] > elem_bb[idim*2+1] )
2905                     {
2906                       elem_bb[idim*2+1] = coords[node*dim+idim] ;
2907                     }
2908                 }
2909             }
2910         }
2911       if(intersectsBoundingBox(bbox, elem_bb, dim, eps))
2912         elems->pushBackSilent(ielem);
2913     }
2914   return elems.retn();
2915 }
2916
2917 /*!
2918  * Returns a type of a cell by its id.
2919  *  \param [in] cellId - the id of the cell of interest.
2920  *  \return INTERP_KERNEL::NormalizedCellType - enumeration item describing the cell type.
2921  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2922  */
2923 INTERP_KERNEL::NormalizedCellType MEDCouplingUMesh::getTypeOfCell(int cellId) const
2924 {
2925   const int *ptI=_nodal_connec_index->getConstPointer();
2926   const int *pt=_nodal_connec->getConstPointer();
2927   if(cellId>=0 && cellId<(int)_nodal_connec_index->getNbOfElems()-1)
2928     return (INTERP_KERNEL::NormalizedCellType) pt[ptI[cellId]];
2929   else
2930     {
2931       std::ostringstream oss; oss << "MEDCouplingUMesh::getTypeOfCell : Requesting type of cell #" << cellId << " but it should be in [0," << _nodal_connec_index->getNbOfElems()-1 << ") !";
2932       throw INTERP_KERNEL::Exception(oss.str().c_str());
2933     }
2934 }
2935
2936 /*!
2937  * This method returns a newly allocated array containing cell ids (ascendingly sorted) whose geometric type are equal to type.
2938  * This method does not throw exception if geometric type \a type is not in \a this.
2939  * This method throws an INTERP_KERNEL::Exception if meshdimension of \b this is not equal to those of \b type.
2940  * The coordinates array is not considered here.
2941  *
2942  * \param [in] type the geometric type
2943  * \return cell ids in this having geometric type \a type.
2944  */
2945 DataArrayInt *MEDCouplingUMesh::giveCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2946 {
2947
2948   MCAuto<DataArrayInt> ret=DataArrayInt::New();
2949   ret->alloc(0,1);
2950   checkConnectivityFullyDefined();
2951   int nbCells=getNumberOfCells();
2952   int mdim=getMeshDimension();
2953   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
2954   if(mdim!=(int)cm.getDimension())
2955     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::giveCellsWithType : Mismatch between mesh dimension and dimension of the cell !");
2956   const int *ptI=_nodal_connec_index->getConstPointer();
2957   const int *pt=_nodal_connec->getConstPointer();
2958   for(int i=0;i<nbCells;i++)
2959     {
2960       if((INTERP_KERNEL::NormalizedCellType)pt[ptI[i]]==type)
2961         ret->pushBackSilent(i);
2962     }
2963   return ret.retn();
2964 }
2965
2966 /*!
2967  * Returns nb of cells having the geometric type \a type. No throw if no cells in \a this has the geometric type \a type.
2968  */
2969 int MEDCouplingUMesh::getNumberOfCellsWithType(INTERP_KERNEL::NormalizedCellType type) const
2970 {
2971   const int *ptI=_nodal_connec_index->getConstPointer();
2972   const int *pt=_nodal_connec->getConstPointer();
2973   int nbOfCells=getNumberOfCells();
2974   int ret=0;
2975   for(int i=0;i<nbOfCells;i++)
2976     if((INTERP_KERNEL::NormalizedCellType) pt[ptI[i]]==type)
2977       ret++;
2978   return ret;
2979 }
2980
2981 /*!
2982  * Returns the nodal connectivity of a given cell.
2983  * The separator of faces within polyhedron connectivity (-1) is not returned, thus
2984  * all returned node ids can be used in getCoordinatesOfNode().
2985  *  \param [in] cellId - an id of the cell of interest.
2986  *  \param [in,out] conn - a vector where the node ids are appended. It is not
2987  *         cleared before the appending.
2988  *  \throw If \a cellId is invalid. Valid range is [0, \a this->getNumberOfCells() ).
2989  */
2990 void MEDCouplingUMesh::getNodeIdsOfCell(int cellId, std::vector<int>& conn) const
2991 {
2992   const int *ptI=_nodal_connec_index->getConstPointer();
2993   const int *pt=_nodal_connec->getConstPointer();
2994   for(const int *w=pt+ptI[cellId]+1;w!=pt+ptI[cellId+1];w++)
2995     if(*w>=0)
2996       conn.push_back(*w);
2997 }
2998
2999 std::string MEDCouplingUMesh::simpleRepr() const
3000 {
3001   static const char msg0[]="No coordinates specified !";
3002   std::ostringstream ret;
3003   ret << "Unstructured mesh with name : \"" << getName() << "\"\n";
3004   ret << "Description of mesh : \"" << getDescription() << "\"\n";
3005   int tmpp1,tmpp2;
3006   double tt=getTime(tmpp1,tmpp2);
3007   ret << "Time attached to the mesh [unit] : " << tt << " [" << getTimeUnit() << "]\n";
3008   ret << "Iteration : " << tmpp1  << " Order : " << tmpp2 << "\n";
3009   if(_mesh_dim>=-1)
3010     { ret << "Mesh dimension : " << _mesh_dim << "\nSpace dimension : "; }
3011   else
3012     { ret << " Mesh dimension has not been set or is invalid !"; }
3013   if(_coords!=0)
3014     {
3015       const int spaceDim=getSpaceDimension();
3016       ret << spaceDim << "\nInfo attached on space dimension : ";
3017       for(int i=0;i<spaceDim;i++)
3018         ret << "\"" << _coords->getInfoOnComponent(i) << "\" ";
3019       ret << "\n";
3020     }
3021   else
3022     ret << msg0 << "\n";
3023   ret << "Number of nodes : ";
3024   if(_coords!=0)
3025     ret << getNumberOfNodes() << "\n";
3026   else
3027     ret << msg0 << "\n";
3028   ret << "Number of cells : ";
3029   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3030     ret << getNumberOfCells() << "\n";
3031   else
3032     ret << "No connectivity specified !" << "\n";
3033   ret << "Cell types present : ";
3034   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=_types.begin();iter!=_types.end();iter++)
3035     {
3036       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(*iter);
3037       ret << cm.getRepr() << " ";
3038     }
3039   ret << "\n";
3040   return ret.str();
3041 }
3042
3043 std::string MEDCouplingUMesh::advancedRepr() const
3044 {
3045   std::ostringstream ret;
3046   ret << simpleRepr();
3047   ret << "\nCoordinates array : \n___________________\n\n";
3048   if(_coords)
3049     _coords->reprWithoutNameStream(ret);
3050   else
3051     ret << "No array set !\n";
3052   ret << "\n\nConnectivity arrays : \n_____________________\n\n";
3053   reprConnectivityOfThisLL(ret);
3054   return ret.str();
3055 }
3056
3057 /*!
3058  * This method returns a C++ code that is a dump of \a this.
3059  * This method will throw if this is not fully defined.
3060  */
3061 std::string MEDCouplingUMesh::cppRepr() const
3062 {
3063   static const char coordsName[]="coords";
3064   static const char connName[]="conn";
3065   static const char connIName[]="connI";
3066   checkFullyDefined();
3067   std::ostringstream ret; ret << "// coordinates" << std::endl;
3068   _coords->reprCppStream(coordsName,ret); ret << std::endl << "// connectivity" << std::endl;
3069   _nodal_connec->reprCppStream(connName,ret); ret << std::endl;
3070   _nodal_connec_index->reprCppStream(connIName,ret); ret << std::endl;
3071   ret << "MEDCouplingUMesh *mesh=MEDCouplingUMesh::New(\"" << getName() << "\"," << getMeshDimension() << ");" << std::endl;
3072   ret << "mesh->setCoords(" << coordsName << ");" << std::endl;
3073   ret << "mesh->setConnectivity(" << connName << "," << connIName << ",true);" << std::endl;
3074   ret << coordsName << "->decrRef(); " << connName << "->decrRef(); " << connIName << "->decrRef();" << std::endl;
3075   return ret.str();
3076 }
3077
3078 std::string MEDCouplingUMesh::reprConnectivityOfThis() const
3079 {
3080   std::ostringstream ret;
3081   reprConnectivityOfThisLL(ret);
3082   return ret.str();
3083 }
3084
3085 /*!
3086  * This method builds a newly allocated instance (with the same name than \a this) that the caller has the responsability to deal with.
3087  * This method returns an instance with all arrays allocated (connectivity, connectivity index, coordinates)
3088  * but with length of these arrays set to 0. It allows to define an "empty" mesh (with nor cells nor nodes but compliant with
3089  * some algos).
3090  * 
3091  * This method expects that \a this has a mesh dimension set and higher or equal to 0. If not an exception will be thrown.
3092  * 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
3093  * with number of tuples set to 0, if not the array is taken as this in the returned instance.
3094  */
3095 MEDCouplingUMesh *MEDCouplingUMesh::buildSetInstanceFromThis(int spaceDim) const
3096 {
3097   int mdim=getMeshDimension();
3098   if(mdim<0)
3099     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSetInstanceFromThis : invalid mesh dimension ! Should be >= 0 !");
3100   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
3101   MCAuto<DataArrayInt> tmp1,tmp2;
3102   bool needToCpyCT=true;
3103   if(!_nodal_connec)
3104     {
3105       tmp1=DataArrayInt::New(); tmp1->alloc(0,1);
3106       needToCpyCT=false;
3107     }
3108   else
3109     {
3110       tmp1=_nodal_connec;
3111       tmp1->incrRef();
3112     }
3113   if(!_nodal_connec_index)
3114     {
3115       tmp2=DataArrayInt::New(); tmp2->alloc(1,1); tmp2->setIJ(0,0,0);
3116       needToCpyCT=false;
3117     }
3118   else
3119     {
3120       tmp2=_nodal_connec_index;
3121       tmp2->incrRef();
3122     }
3123   ret->setConnectivity(tmp1,tmp2,false);
3124   if(needToCpyCT)
3125     ret->_types=_types;
3126   if(!_coords)
3127     {
3128       MCAuto<DataArrayDouble> coords=DataArrayDouble::New(); coords->alloc(0,spaceDim);
3129       ret->setCoords(coords);
3130     }
3131   else
3132     ret->setCoords(_coords);
3133   return ret.retn();
3134 }
3135
3136 void MEDCouplingUMesh::reprConnectivityOfThisLL(std::ostringstream& stream) const
3137 {
3138   if(_nodal_connec!=0 && _nodal_connec_index!=0)
3139     {
3140       int nbOfCells=getNumberOfCells();
3141       const int *c=_nodal_connec->getConstPointer();
3142       const int *ci=_nodal_connec_index->getConstPointer();
3143       for(int i=0;i<nbOfCells;i++)
3144         {
3145           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[i]]);
3146           stream << "Cell #" << i << " " << cm.getRepr() << " : ";
3147           std::copy(c+ci[i]+1,c+ci[i+1],std::ostream_iterator<int>(stream," "));
3148           stream << "\n";
3149         }
3150     }
3151   else
3152     stream << "Connectivity not defined !\n";
3153 }
3154
3155 int MEDCouplingUMesh::getNumberOfNodesInCell(int cellId) const
3156 {
3157   const int *ptI=_nodal_connec_index->getConstPointer();
3158   const int *pt=_nodal_connec->getConstPointer();
3159   if(pt[ptI[cellId]]!=INTERP_KERNEL::NORM_POLYHED)
3160     return ptI[cellId+1]-ptI[cellId]-1;
3161   else
3162     return (int)std::count_if(pt+ptI[cellId]+1,pt+ptI[cellId+1],std::bind2nd(std::not_equal_to<int>(),-1));
3163 }
3164
3165 /*!
3166  * Returns types of cells of the specified part of \a this mesh.
3167  * This method avoids computing sub-mesh explicitely to get its types.
3168  *  \param [in] begin - an array of cell ids of interest.
3169  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3170  *  \return std::set<INTERP_KERNEL::NormalizedCellType> - a set of enumeration items
3171  *         describing the cell types. 
3172  *  \throw If the coordinates array is not set.
3173  *  \throw If the nodal connectivity of cells is not defined.
3174  *  \sa getAllGeoTypes()
3175  */
3176 std::set<INTERP_KERNEL::NormalizedCellType> MEDCouplingUMesh::getTypesOfPart(const int *begin, const int *end) const
3177 {
3178   checkFullyDefined();
3179   std::set<INTERP_KERNEL::NormalizedCellType> ret;
3180   const int *conn=_nodal_connec->getConstPointer();
3181   const int *connIndex=_nodal_connec_index->getConstPointer();
3182   for(const int *w=begin;w!=end;w++)
3183     ret.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]);
3184   return ret;
3185 }
3186
3187 /*!
3188  * Defines the nodal connectivity using given connectivity arrays in \ref numbering-indirect format.
3189  * Optionally updates
3190  * a set of types of cells constituting \a this mesh. 
3191  * This method is for advanced users having prepared their connectivity before. For
3192  * more info on using this method see \ref MEDCouplingUMeshAdvBuild.
3193  *  \param [in] conn - the nodal connectivity array. 
3194  *  \param [in] connIndex - the nodal connectivity index array.
3195  *  \param [in] isComputingTypes - if \c true, the set of types constituting \a this
3196  *         mesh is updated.
3197  */
3198 void MEDCouplingUMesh::setConnectivity(DataArrayInt *conn, DataArrayInt *connIndex, bool isComputingTypes)
3199 {
3200   DataArrayInt::SetArrayIn(conn,_nodal_connec);
3201   DataArrayInt::SetArrayIn(connIndex,_nodal_connec_index);
3202   if(isComputingTypes)
3203     computeTypes();
3204   declareAsNew();
3205 }
3206
3207 /*!
3208  * Copy constructor. If 'deepCopy' is false \a this is a shallow copy of other.
3209  * If 'deeCpy' is true all arrays (coordinates and connectivities) are deeply copied.
3210  */
3211 MEDCouplingUMesh::MEDCouplingUMesh(const MEDCouplingUMesh& other, bool deepCopy):MEDCouplingPointSet(other,deepCopy),_mesh_dim(other._mesh_dim),
3212     _nodal_connec(0),_nodal_connec_index(0),
3213     _types(other._types)
3214 {
3215   if(other._nodal_connec)
3216     _nodal_connec=other._nodal_connec->performCopyOrIncrRef(deepCopy);
3217   if(other._nodal_connec_index)
3218     _nodal_connec_index=other._nodal_connec_index->performCopyOrIncrRef(deepCopy);
3219 }
3220
3221 MEDCouplingUMesh::~MEDCouplingUMesh()
3222 {
3223   if(_nodal_connec)
3224     _nodal_connec->decrRef();
3225   if(_nodal_connec_index)
3226     _nodal_connec_index->decrRef();
3227 }
3228
3229 /*!
3230  * Recomputes a set of cell types of \a this mesh. For more info see
3231  * \ref MEDCouplingUMeshNodalConnectivity.
3232  */
3233 void MEDCouplingUMesh::computeTypes()
3234 {
3235   ComputeAllTypesInternal(_types,_nodal_connec,_nodal_connec_index);
3236 }
3237
3238 /*!
3239  * This method checks that all arrays are set. If yes nothing done if no an exception is thrown.
3240  */
3241 void MEDCouplingUMesh::checkFullyDefined() const
3242 {
3243   if(!_nodal_connec_index || !_nodal_connec || !_coords)
3244     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity and coordinates set in unstructured mesh.");
3245 }
3246
3247 /*!
3248  * This method checks that all connectivity arrays are set. If yes nothing done if no an exception is thrown.
3249  */
3250 void MEDCouplingUMesh::checkConnectivityFullyDefined() const
3251 {
3252   if(!_nodal_connec_index || !_nodal_connec)
3253     throw INTERP_KERNEL::Exception("Reverse nodal connectivity computation requires full connectivity set in unstructured mesh.");
3254 }
3255
3256 /*!
3257  * Returns a number of cells constituting \a this mesh. 
3258  *  \return int - the number of cells in \a this mesh.
3259  *  \throw If the nodal connectivity of cells is not defined.
3260  */
3261 int MEDCouplingUMesh::getNumberOfCells() const
3262
3263   if(_nodal_connec_index)
3264     return _nodal_connec_index->getNumberOfTuples()-1;
3265   else
3266     if(_mesh_dim==-1)
3267       return 1;
3268     else
3269       throw INTERP_KERNEL::Exception("Unable to get number of cells because no connectivity specified !");
3270 }
3271
3272 /*!
3273  * Returns a dimension of \a this mesh, i.e. a dimension of cells constituting \a this
3274  * mesh. For more info see \ref meshes.
3275  *  \return int - the dimension of \a this mesh.
3276  *  \throw If the mesh dimension is not defined using setMeshDimension().
3277  */
3278 int MEDCouplingUMesh::getMeshDimension() const
3279 {
3280   if(_mesh_dim<-1)
3281     throw INTERP_KERNEL::Exception("No mesh dimension specified !");
3282   return _mesh_dim;
3283 }
3284
3285 /*!
3286  * Returns a length of the nodal connectivity array.
3287  * This method is for test reason. Normally the integer returned is not useable by
3288  * user.  For more info see \ref MEDCouplingUMeshNodalConnectivity.
3289  *  \return int - the length of the nodal connectivity array.
3290  */
3291 int MEDCouplingUMesh::getNodalConnectivityArrayLen() const
3292 {
3293   return _nodal_connec->getNbOfElems();
3294 }
3295
3296 /*!
3297  * First step of serialization process. Used by ParaMEDMEM and MEDCouplingCorba to transfert data between process.
3298  */
3299 void MEDCouplingUMesh::getTinySerializationInformation(std::vector<double>& tinyInfoD, std::vector<int>& tinyInfo, std::vector<std::string>& littleStrings) const
3300 {
3301   MEDCouplingPointSet::getTinySerializationInformation(tinyInfoD,tinyInfo,littleStrings);
3302   tinyInfo.push_back(getMeshDimension());
3303   tinyInfo.push_back(getNumberOfCells());
3304   if(_nodal_connec)
3305     tinyInfo.push_back(getNodalConnectivityArrayLen());
3306   else
3307     tinyInfo.push_back(-1);
3308 }
3309
3310 /*!
3311  * First step of unserialization process.
3312  */
3313 bool MEDCouplingUMesh::isEmptyMesh(const std::vector<int>& tinyInfo) const
3314 {
3315   return tinyInfo[6]<=0;
3316 }
3317
3318 /*!
3319  * Second step of serialization process.
3320  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3321  * \param a1
3322  * \param a2
3323  * \param littleStrings
3324  */
3325 void MEDCouplingUMesh::resizeForUnserialization(const std::vector<int>& tinyInfo, DataArrayInt *a1, DataArrayDouble *a2, std::vector<std::string>& littleStrings) const
3326 {
3327   MEDCouplingPointSet::resizeForUnserialization(tinyInfo,a1,a2,littleStrings);
3328   if(tinyInfo[5]!=-1)
3329     a1->alloc(tinyInfo[7]+tinyInfo[6]+1,1);
3330 }
3331
3332 /*!
3333  * Third and final step of serialization process.
3334  */
3335 void MEDCouplingUMesh::serialize(DataArrayInt *&a1, DataArrayDouble *&a2) const
3336 {
3337   MEDCouplingPointSet::serialize(a1,a2);
3338   if(getMeshDimension()>-1)
3339     {
3340       a1=DataArrayInt::New();
3341       a1->alloc(getNodalConnectivityArrayLen()+getNumberOfCells()+1,1);
3342       int *ptA1=a1->getPointer();
3343       const int *conn=getNodalConnectivity()->getConstPointer();
3344       const int *index=getNodalConnectivityIndex()->getConstPointer();
3345       ptA1=std::copy(index,index+getNumberOfCells()+1,ptA1);
3346       std::copy(conn,conn+getNodalConnectivityArrayLen(),ptA1);
3347     }
3348   else
3349     a1=0;
3350 }
3351
3352 /*!
3353  * Second and final unserialization process.
3354  * \param tinyInfo must be equal to the result given by getTinySerializationInformation method.
3355  */
3356 void MEDCouplingUMesh::unserialization(const std::vector<double>& tinyInfoD, const std::vector<int>& tinyInfo, const DataArrayInt *a1, DataArrayDouble *a2, const std::vector<std::string>& littleStrings)
3357 {
3358   MEDCouplingPointSet::unserialization(tinyInfoD,tinyInfo,a1,a2,littleStrings);
3359   setMeshDimension(tinyInfo[5]);
3360   if(tinyInfo[7]!=-1)
3361     {
3362       // Connectivity
3363       const int *recvBuffer=a1->getConstPointer();
3364       MCAuto<DataArrayInt> myConnecIndex=DataArrayInt::New();
3365       myConnecIndex->alloc(tinyInfo[6]+1,1);
3366       std::copy(recvBuffer,recvBuffer+tinyInfo[6]+1,myConnecIndex->getPointer());
3367       MCAuto<DataArrayInt> myConnec=DataArrayInt::New();
3368       myConnec->alloc(tinyInfo[7],1);
3369       std::copy(recvBuffer+tinyInfo[6]+1,recvBuffer+tinyInfo[6]+1+tinyInfo[7],myConnec->getPointer());
3370       setConnectivity(myConnec, myConnecIndex);
3371     }
3372 }
3373
3374 /*!
3375  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelfSlice.
3376  * CellIds are given using range specified by a start an end and step.
3377  */
3378 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice(int start, int end, int step) const
3379 {
3380   checkFullyDefined();
3381   int ncell=getNumberOfCells();
3382   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3383   ret->_mesh_dim=_mesh_dim;
3384   ret->setCoords(_coords);
3385   int newNbOfCells=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : ");
3386   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(newNbOfCells+1,1);
3387   int *newConnIPtr=newConnI->getPointer(); *newConnIPtr=0;
3388   int work=start;
3389   const int *conn=_nodal_connec->getConstPointer();
3390   const int *connIndex=_nodal_connec_index->getConstPointer();
3391   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3392     {
3393       if(work>=0 && work<ncell)
3394         {
3395           newConnIPtr[1]=newConnIPtr[0]+connIndex[work+1]-connIndex[work];
3396         }
3397       else
3398         {
3399           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoordsSlice : On pos #" << i << " input cell id =" << work << " should be in [0," << ncell << ") !";
3400           throw INTERP_KERNEL::Exception(oss.str().c_str());
3401         }
3402     }
3403   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(newConnIPtr[0],1);
3404   int *newConnPtr=newConn->getPointer();
3405   std::set<INTERP_KERNEL::NormalizedCellType> types;
3406   work=start;
3407   for(int i=0;i<newNbOfCells;i++,newConnIPtr++,work+=step)
3408     {
3409       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[work]]);
3410       newConnPtr=std::copy(conn+connIndex[work],conn+connIndex[work+1],newConnPtr);
3411     }
3412   ret->setConnectivity(newConn,newConnI,false);
3413   ret->_types=types;
3414   ret->copyTinyInfoFrom(this);
3415   return ret.retn();
3416 }
3417
3418 /*!
3419  * This is the low algorithm of MEDCouplingUMesh::buildPartOfMySelf.
3420  * Keeps from \a this only cells which constituing point id are in the ids specified by [ \a begin,\a end ).
3421  * The return newly allocated mesh will share the same coordinates as \a this.
3422  */
3423 MEDCouplingUMesh *MEDCouplingUMesh::buildPartOfMySelfKeepCoords(const int *begin, const int *end) const
3424 {
3425   checkConnectivityFullyDefined();
3426   int ncell=getNumberOfCells();
3427   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New();
3428   ret->_mesh_dim=_mesh_dim;
3429   ret->setCoords(_coords);
3430   std::size_t nbOfElemsRet=std::distance(begin,end);
3431   int *connIndexRet=(int *)malloc((nbOfElemsRet+1)*sizeof(int));
3432   connIndexRet[0]=0;
3433   const int *conn=_nodal_connec->getConstPointer();
3434   const int *connIndex=_nodal_connec_index->getConstPointer();
3435   int newNbring=0;
3436   for(const int *work=begin;work!=end;work++,newNbring++)
3437     {
3438       if(*work>=0 && *work<ncell)
3439         connIndexRet[newNbring+1]=connIndexRet[newNbring]+connIndex[*work+1]-connIndex[*work];
3440       else
3441         {
3442           free(connIndexRet);
3443           std::ostringstream oss; oss << "MEDCouplingUMesh::buildPartOfMySelfKeepCoords : On pos #" << std::distance(begin,work) << " input cell id =" << *work << " should be in [0," << ncell << ") !";
3444           throw INTERP_KERNEL::Exception(oss.str().c_str());
3445         }
3446     }
3447   int *connRet=(int *)malloc(connIndexRet[nbOfElemsRet]*sizeof(int));
3448   int *connRetWork=connRet;
3449   std::set<INTERP_KERNEL::NormalizedCellType> types;
3450   for(const int *work=begin;work!=end;work++)
3451     {
3452       types.insert((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*work]]);
3453       connRetWork=std::copy(conn+connIndex[*work],conn+connIndex[*work+1],connRetWork);
3454     }
3455   MCAuto<DataArrayInt> connRetArr=DataArrayInt::New();
3456   connRetArr->useArray(connRet,true,C_DEALLOC,connIndexRet[nbOfElemsRet],1);
3457   MCAuto<DataArrayInt> connIndexRetArr=DataArrayInt::New();
3458   connIndexRetArr->useArray(connIndexRet,true,C_DEALLOC,(int)nbOfElemsRet+1,1);
3459   ret->setConnectivity(connRetArr,connIndexRetArr,false);
3460   ret->_types=types;
3461   ret->copyTinyInfoFrom(this);
3462   return ret.retn();
3463 }
3464
3465 /*!
3466  * Returns a new MEDCouplingFieldDouble containing volumes of cells constituting \a this
3467  * mesh.<br>
3468  * For 1D cells, the returned field contains lengths.<br>
3469  * For 2D cells, the returned field contains areas.<br>
3470  * For 3D cells, the returned field contains volumes.
3471  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3472  *         orientation, i.e. the volume is always positive.
3473  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on cells
3474  *         and one time . The caller is to delete this field using decrRef() as it is no
3475  *         more needed.
3476  */
3477 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureField(bool isAbs) const
3478 {
3479   std::string name="MeasureOfMesh_";
3480   name+=getName();
3481   int nbelem=getNumberOfCells();
3482   MCAuto<MEDCouplingFieldDouble> field=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3483   field->setName(name);
3484   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3485   array->alloc(nbelem,1);
3486   double *area_vol=array->getPointer();
3487   field->setArray(array) ; array=0;
3488   field->setMesh(const_cast<MEDCouplingUMesh *>(this));
3489   field->synchronizeTimeWithMesh();
3490   if(getMeshDimension()!=-1)
3491     {
3492       int ipt;
3493       INTERP_KERNEL::NormalizedCellType type;
3494       int dim_space=getSpaceDimension();
3495       const double *coords=getCoords()->getConstPointer();
3496       const int *connec=getNodalConnectivity()->getConstPointer();
3497       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3498       for(int iel=0;iel<nbelem;iel++)
3499         {
3500           ipt=connec_index[iel];
3501           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3502           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);
3503         }
3504       if(isAbs)
3505         std::transform(area_vol,area_vol+nbelem,area_vol,std::ptr_fun<double,double>(fabs));
3506     }
3507   else
3508     {
3509       area_vol[0]=std::numeric_limits<double>::max();
3510     }
3511   return field.retn();
3512 }
3513
3514 /*!
3515  * Returns a new DataArrayDouble containing volumes of specified cells of \a this
3516  * mesh.<br>
3517  * For 1D cells, the returned array contains lengths.<br>
3518  * For 2D cells, the returned array contains areas.<br>
3519  * For 3D cells, the returned array contains volumes.
3520  * This method avoids building explicitly a part of \a this mesh to perform the work.
3521  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3522  *         orientation, i.e. the volume is always positive.
3523  *  \param [in] begin - an array of cell ids of interest.
3524  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3525  *  \return DataArrayDouble * - a new instance of DataArrayDouble. The caller is to
3526  *          delete this array using decrRef() as it is no more needed.
3527  * 
3528  *  \if ENABLE_EXAMPLES
3529  *  \ref cpp_mcumesh_getPartMeasureField "Here is a C++ example".<br>
3530  *  \ref  py_mcumesh_getPartMeasureField "Here is a Python example".
3531  *  \endif
3532  *  \sa getMeasureField()
3533  */
3534 DataArrayDouble *MEDCouplingUMesh::getPartMeasureField(bool isAbs, const int *begin, const int *end) const
3535 {
3536   std::string name="PartMeasureOfMesh_";
3537   name+=getName();
3538   int nbelem=(int)std::distance(begin,end);
3539   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3540   array->setName(name);
3541   array->alloc(nbelem,1);
3542   double *area_vol=array->getPointer();
3543   if(getMeshDimension()!=-1)
3544     {
3545       int ipt;
3546       INTERP_KERNEL::NormalizedCellType type;
3547       int dim_space=getSpaceDimension();
3548       const double *coords=getCoords()->getConstPointer();
3549       const int *connec=getNodalConnectivity()->getConstPointer();
3550       const int *connec_index=getNodalConnectivityIndex()->getConstPointer();
3551       for(const int *iel=begin;iel!=end;iel++)
3552         {
3553           ipt=connec_index[*iel];
3554           type=(INTERP_KERNEL::NormalizedCellType)connec[ipt];
3555           *area_vol++=INTERP_KERNEL::computeVolSurfOfCell2<int,INTERP_KERNEL::ALL_C_MODE>(type,connec+ipt+1,connec_index[*iel+1]-ipt-1,coords,dim_space);
3556         }
3557       if(isAbs)
3558         std::transform(array->getPointer(),area_vol,array->getPointer(),std::ptr_fun<double,double>(fabs));
3559     }
3560   else
3561     {
3562       area_vol[0]=std::numeric_limits<double>::max();
3563     }
3564   return array.retn();
3565 }
3566
3567 /*!
3568  * Returns a new MEDCouplingFieldDouble containing volumes of cells of a dual mesh of
3569  * \a this one. The returned field contains the dual cell volume for each corresponding
3570  * node in \a this mesh. In other words, the field returns the getMeasureField() of
3571  *  the dual mesh in P1 sens of \a this.<br>
3572  * For 1D cells, the returned field contains lengths.<br>
3573  * For 2D cells, the returned field contains areas.<br>
3574  * For 3D cells, the returned field contains volumes.
3575  * This method is useful to check "P1*" conservative interpolators.
3576  *  \param [in] isAbs - if \c true, the computed cell volume does not reflect cell
3577  *         orientation, i.e. the volume is always positive.
3578  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3579  *          nodes and one time. The caller is to delete this array using decrRef() as
3580  *          it is no more needed.
3581  */
3582 MEDCouplingFieldDouble *MEDCouplingUMesh::getMeasureFieldOnNode(bool isAbs) const
3583 {
3584   MCAuto<MEDCouplingFieldDouble> tmp=getMeasureField(isAbs);
3585   std::string name="MeasureOnNodeOfMesh_";
3586   name+=getName();
3587   int nbNodes=getNumberOfNodes();
3588   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_NODES);
3589   double cst=1./((double)getMeshDimension()+1.);
3590   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3591   array->alloc(nbNodes,1);
3592   double *valsToFill=array->getPointer();
3593   std::fill(valsToFill,valsToFill+nbNodes,0.);
3594   const double *values=tmp->getArray()->getConstPointer();
3595   MCAuto<DataArrayInt> da=DataArrayInt::New();
3596   MCAuto<DataArrayInt> daInd=DataArrayInt::New();
3597   getReverseNodalConnectivity(da,daInd);
3598   const int *daPtr=da->getConstPointer();
3599   const int *daIPtr=daInd->getConstPointer();
3600   for(int i=0;i<nbNodes;i++)
3601     for(const int *cell=daPtr+daIPtr[i];cell!=daPtr+daIPtr[i+1];cell++)
3602       valsToFill[i]+=cst*values[*cell];
3603   ret->setMesh(this);
3604   ret->setArray(array);
3605   return ret.retn();
3606 }
3607
3608 /*!
3609  * Returns a new MEDCouplingFieldDouble holding normal vectors to cells of \a this
3610  * mesh. The returned normal vectors to each cell have a norm2 equal to 1.
3611  * The computed vectors have <em> this->getMeshDimension()+1 </em> components
3612  * and are normalized.
3613  * <br> \a this can be either 
3614  * - a  2D mesh in 2D or 3D space or 
3615  * - an 1D mesh in 2D space.
3616  * 
3617  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3618  *          cells and one time. The caller is to delete this field using decrRef() as
3619  *          it is no more needed.
3620  *  \throw If the nodal connectivity of cells is not defined.
3621  *  \throw If the coordinates array is not set.
3622  *  \throw If the mesh dimension is not set.
3623  *  \throw If the mesh and space dimension is not as specified above.
3624  */
3625 MEDCouplingFieldDouble *MEDCouplingUMesh::buildOrthogonalField() const
3626 {
3627   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3628     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3629   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3630   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3631   int nbOfCells=getNumberOfCells();
3632   int nbComp=getMeshDimension()+1;
3633   array->alloc(nbOfCells,nbComp);
3634   double *vals=array->getPointer();
3635   const int *connI=_nodal_connec_index->getConstPointer();
3636   const int *conn=_nodal_connec->getConstPointer();
3637   const double *coords=_coords->getConstPointer();
3638   if(getMeshDimension()==2)
3639     {
3640       if(getSpaceDimension()==3)
3641         {
3642           MCAuto<DataArrayDouble> loc=computeCellCenterOfMass();
3643           const double *locPtr=loc->getConstPointer();
3644           for(int i=0;i<nbOfCells;i++,vals+=3)
3645             {
3646               int offset=connI[i];
3647               INTERP_KERNEL::crossprod<3>(locPtr+3*i,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3648               double n=INTERP_KERNEL::norm<3>(vals);
3649               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3650             }
3651         }
3652       else
3653         {
3654           MCAuto<MEDCouplingFieldDouble> isAbs=getMeasureField(false);
3655           const double *isAbsPtr=isAbs->getArray()->begin();
3656           for(int i=0;i<nbOfCells;i++,isAbsPtr++)
3657             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=*isAbsPtr>0.?1.:-1.; }
3658         }
3659     }
3660   else//meshdimension==1
3661     {
3662       double tmp[2];
3663       for(int i=0;i<nbOfCells;i++)
3664         {
3665           int offset=connI[i];
3666           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3667           double n=INTERP_KERNEL::norm<2>(tmp);
3668           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3669           *vals++=-tmp[1];
3670           *vals++=tmp[0];
3671         }
3672     }
3673   ret->setArray(array);
3674   ret->setMesh(this);
3675   ret->synchronizeTimeWithSupport();
3676   return ret.retn();
3677 }
3678
3679 /*!
3680  * Returns a new MEDCouplingFieldDouble holding normal vectors to specified cells of
3681  * \a this mesh. The computed vectors have <em> this->getMeshDimension()+1 </em> components
3682  * and are normalized.
3683  * <br> \a this can be either 
3684  * - a  2D mesh in 2D or 3D space or 
3685  * - an 1D mesh in 2D space.
3686  * 
3687  * This method avoids building explicitly a part of \a this mesh to perform the work.
3688  *  \param [in] begin - an array of cell ids of interest.
3689  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
3690  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3691  *          cells and one time. The caller is to delete this field using decrRef() as
3692  *          it is no more needed.
3693  *  \throw If the nodal connectivity of cells is not defined.
3694  *  \throw If the coordinates array is not set.
3695  *  \throw If the mesh dimension is not set.
3696  *  \throw If the mesh and space dimension is not as specified above.
3697  *  \sa buildOrthogonalField()
3698  *
3699  *  \if ENABLE_EXAMPLES
3700  *  \ref cpp_mcumesh_buildPartOrthogonalField "Here is a C++ example".<br>
3701  *  \ref  py_mcumesh_buildPartOrthogonalField "Here is a Python example".
3702  *  \endif
3703  */
3704 MEDCouplingFieldDouble *MEDCouplingUMesh::buildPartOrthogonalField(const int *begin, const int *end) const
3705 {
3706   if((getMeshDimension()!=2) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
3707     throw INTERP_KERNEL::Exception("Expected a umesh with ( meshDim == 2 spaceDim == 2 or 3 ) or ( meshDim == 1 spaceDim == 2 ) !");
3708   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3709   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3710   std::size_t nbelems=std::distance(begin,end);
3711   int nbComp=getMeshDimension()+1;
3712   array->alloc((int)nbelems,nbComp);
3713   double *vals=array->getPointer();
3714   const int *connI=_nodal_connec_index->getConstPointer();
3715   const int *conn=_nodal_connec->getConstPointer();
3716   const double *coords=_coords->getConstPointer();
3717   if(getMeshDimension()==2)
3718     {
3719       if(getSpaceDimension()==3)
3720         {
3721           MCAuto<DataArrayDouble> loc=getPartBarycenterAndOwner(begin,end);
3722           const double *locPtr=loc->getConstPointer();
3723           for(const int *i=begin;i!=end;i++,vals+=3,locPtr+=3)
3724             {
3725               int offset=connI[*i];
3726               INTERP_KERNEL::crossprod<3>(locPtr,coords+3*conn[offset+1],coords+3*conn[offset+2],vals);
3727               double n=INTERP_KERNEL::norm<3>(vals);
3728               std::transform(vals,vals+3,vals,std::bind2nd(std::multiplies<double>(),1./n));
3729             }
3730         }
3731       else
3732         {
3733           for(std::size_t i=0;i<nbelems;i++)
3734             { vals[3*i]=0.; vals[3*i+1]=0.; vals[3*i+2]=1.; }
3735         }
3736     }
3737   else//meshdimension==1
3738     {
3739       double tmp[2];
3740       for(const int *i=begin;i!=end;i++)
3741         {
3742           int offset=connI[*i];
3743           std::transform(coords+2*conn[offset+2],coords+2*conn[offset+2]+2,coords+2*conn[offset+1],tmp,std::minus<double>());
3744           double n=INTERP_KERNEL::norm<2>(tmp);
3745           std::transform(tmp,tmp+2,tmp,std::bind2nd(std::multiplies<double>(),1./n));
3746           *vals++=-tmp[1];
3747           *vals++=tmp[0];
3748         }
3749     }
3750   ret->setArray(array);
3751   ret->setMesh(this);
3752   ret->synchronizeTimeWithSupport();
3753   return ret.retn();
3754 }
3755
3756 /*!
3757  * Returns a new MEDCouplingFieldDouble holding a direction vector for each SEG2 in \a
3758  * this 1D mesh. The computed vectors have <em> this->getSpaceDimension() </em> components
3759  * and are \b not normalized.
3760  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
3761  *          cells and one time. The caller is to delete this field using decrRef() as
3762  *          it is no more needed.
3763  *  \throw If the nodal connectivity of cells is not defined.
3764  *  \throw If the coordinates array is not set.
3765  *  \throw If \a this->getMeshDimension() != 1.
3766  *  \throw If \a this mesh includes cells of type other than SEG2.
3767  */
3768 MEDCouplingFieldDouble *MEDCouplingUMesh::buildDirectionVectorField() const
3769 {
3770   if(getMeshDimension()!=1)
3771     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for buildDirectionVectorField !");
3772   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
3773     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for buildDirectionVectorField !");
3774   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
3775   MCAuto<DataArrayDouble> array=DataArrayDouble::New();
3776   int nbOfCells=getNumberOfCells();
3777   int spaceDim=getSpaceDimension();
3778   array->alloc(nbOfCells,spaceDim);
3779   double *pt=array->getPointer();
3780   const double *coo=getCoords()->getConstPointer();
3781   std::vector<int> conn;
3782   conn.reserve(2);
3783   for(int i=0;i<nbOfCells;i++)
3784     {
3785       conn.resize(0);
3786       getNodeIdsOfCell(i,conn);
3787       pt=std::transform(coo+conn[1]*spaceDim,coo+(conn[1]+1)*spaceDim,coo+conn[0]*spaceDim,pt,std::minus<double>());
3788     }
3789   ret->setArray(array);
3790   ret->setMesh(this);
3791   ret->synchronizeTimeWithSupport();
3792   return ret.retn();
3793 }
3794
3795 /*!
3796  * Creates a 2D mesh by cutting \a this 3D mesh with a plane. In addition to the mesh,
3797  * returns a new DataArrayInt, of length equal to the number of 2D cells in the result
3798  * mesh, holding, for each cell in the result mesh, an id of a 3D cell it comes
3799  * from. If a result face is shared by two 3D cells, then the face in included twice in
3800  * the result mesh.
3801  *  \param [in] origin - 3 components of a point defining location of the plane.
3802  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3803  *         must be greater than 1e-6.
3804  *  \param [in] eps - half-thickness of the plane.
3805  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of 3D cells
3806  *         producing correspondent 2D cells. The caller is to delete this array
3807  *         using decrRef() as it is no more needed.
3808  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This mesh does
3809  *         not share the node coordinates array with \a this mesh. The caller is to
3810  *         delete this mesh using decrRef() as it is no more needed.  
3811  *  \throw If the coordinates array is not set.
3812  *  \throw If the nodal connectivity of cells is not defined.
3813  *  \throw If \a this->getMeshDimension() != 3 or \a this->getSpaceDimension() != 3.
3814  *  \throw If magnitude of \a vec is less than 1e-6.
3815  *  \throw If the plane does not intersect any 3D cell of \a this mesh.
3816  *  \throw If \a this includes quadratic cells.
3817  */
3818 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3D(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3819 {
3820   checkFullyDefined();
3821   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
3822     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
3823   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3824   if(candidates->empty())
3825     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane considering bounding boxes !");
3826   std::vector<int> nodes;
3827   DataArrayInt *cellIds1D=0;
3828   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3829   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3830   MCAuto<DataArrayInt> desc1=DataArrayInt::New(),desc2=DataArrayInt::New();
3831   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New(),descIndx2=DataArrayInt::New();
3832   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New(),revDesc2=DataArrayInt::New();
3833   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New(),revDescIndx2=DataArrayInt::New();
3834   MCAuto<MEDCouplingUMesh> mDesc2=subMesh->buildDescendingConnectivity(desc2,descIndx2,revDesc2,revDescIndx2);//meshDim==2 spaceDim==3
3835   revDesc2=0; revDescIndx2=0;
3836   MCAuto<MEDCouplingUMesh> mDesc1=mDesc2->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3837   revDesc1=0; revDescIndx1=0;
3838   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3839   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3840   //
3841   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3842   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3843     cut3DCurve[*it]=-1;
3844   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3845   std::vector< std::pair<int,int> > cut3DSurf(mDesc2->getNumberOfCells());
3846   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,mDesc2->getNodalConnectivity()->getConstPointer(),mDesc2->getNodalConnectivityIndex()->getConstPointer(),
3847                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3848                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3849   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New());
3850   connI->pushBackSilent(0); conn->alloc(0,1); cellIds2->alloc(0,1);
3851   subMesh->assemblyForSplitFrom3DSurf(cut3DSurf,desc2->getConstPointer(),descIndx2->getConstPointer(),conn,connI,cellIds2);
3852   if(cellIds2->empty())
3853     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D : No 3D cells in this intercepts the specified plane !");
3854   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3D",2);
3855   ret->setCoords(mDesc1->getCoords());
3856   ret->setConnectivity(conn,connI,true);
3857   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3858   return ret.retn();
3859 }
3860
3861 /*!
3862  * Creates an 1D mesh by cutting \a this 2D mesh in 3D space with a plane. In
3863 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
3864 from. If a result segment is shared by two 2D cells, then the segment in included twice in
3865 the result mesh.
3866  *  \param [in] origin - 3 components of a point defining location of the plane.
3867  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3868  *         must be greater than 1e-6.
3869  *  \param [in] eps - half-thickness of the plane.
3870  *  \param [out] cellIds - a new instance of DataArrayInt holding ids of faces
3871  *         producing correspondent segments. The caller is to delete this array
3872  *         using decrRef() as it is no more needed.
3873  *  \return MEDCouplingUMesh * - a new instance of MEDCouplingUMesh. This is an 1D
3874  *         mesh in 3D space. This mesh does not share the node coordinates array with
3875  *         \a this mesh. The caller is to delete this mesh using decrRef() as it is
3876  *         no more needed. 
3877  *  \throw If the coordinates array is not set.
3878  *  \throw If the nodal connectivity of cells is not defined.
3879  *  \throw If \a this->getMeshDimension() != 2 or \a this->getSpaceDimension() != 3.
3880  *  \throw If magnitude of \a vec is less than 1e-6.
3881  *  \throw If the plane does not intersect any 2D cell of \a this mesh.
3882  *  \throw If \a this includes quadratic cells.
3883  */
3884 MEDCouplingUMesh *MEDCouplingUMesh::buildSlice3DSurf(const double *origin, const double *vec, double eps, DataArrayInt *&cellIds) const
3885 {
3886   checkFullyDefined();
3887   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
3888     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf works on umeshes with meshdim equal to 2 and spaceDim equal to 3 !");
3889   MCAuto<DataArrayInt> candidates=getCellIdsCrossingPlane(origin,vec,eps);
3890   if(candidates->empty())
3891     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3D surf cells in this intercepts the specified plane considering bounding boxes !");
3892   std::vector<int> nodes;
3893   DataArrayInt *cellIds1D=0;
3894   MCAuto<MEDCouplingUMesh> subMesh=static_cast<MEDCouplingUMesh*>(buildPartOfMySelf(candidates->begin(),candidates->end(),false));
3895   subMesh->findNodesOnPlane(origin,vec,eps,nodes);
3896   MCAuto<DataArrayInt> desc1=DataArrayInt::New();
3897   MCAuto<DataArrayInt> descIndx1=DataArrayInt::New();
3898   MCAuto<DataArrayInt> revDesc1=DataArrayInt::New();
3899   MCAuto<DataArrayInt> revDescIndx1=DataArrayInt::New();
3900   MCAuto<MEDCouplingUMesh> mDesc1=subMesh->buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1);//meshDim==1 spaceDim==3
3901   mDesc1->fillCellIdsToKeepFromNodeIds(&nodes[0],&nodes[0]+nodes.size(),true,cellIds1D);
3902   MCAuto<DataArrayInt> cellIds1DTmp(cellIds1D);
3903   //
3904   std::vector<int> cut3DCurve(mDesc1->getNumberOfCells(),-2);
3905   for(const int *it=cellIds1D->begin();it!=cellIds1D->end();it++)
3906     cut3DCurve[*it]=-1;
3907   mDesc1->split3DCurveWithPlane(origin,vec,eps,cut3DCurve);
3908   int ncellsSub=subMesh->getNumberOfCells();
3909   std::vector< std::pair<int,int> > cut3DSurf(ncellsSub);
3910   AssemblyForSplitFrom3DCurve(cut3DCurve,nodes,subMesh->getNodalConnectivity()->getConstPointer(),subMesh->getNodalConnectivityIndex()->getConstPointer(),
3911                               mDesc1->getNodalConnectivity()->getConstPointer(),mDesc1->getNodalConnectivityIndex()->getConstPointer(),
3912                               desc1->getConstPointer(),descIndx1->getConstPointer(),cut3DSurf);
3913   MCAuto<DataArrayInt> conn(DataArrayInt::New()),connI(DataArrayInt::New()),cellIds2(DataArrayInt::New()); connI->pushBackSilent(0);
3914   conn->alloc(0,1);
3915   const int *nodal=subMesh->getNodalConnectivity()->getConstPointer();
3916   const int *nodalI=subMesh->getNodalConnectivityIndex()->getConstPointer();
3917   for(int i=0;i<ncellsSub;i++)
3918     {
3919       if(cut3DSurf[i].first!=-1 && cut3DSurf[i].second!=-1)
3920         {
3921           if(cut3DSurf[i].first!=-2)
3922             {
3923               conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(cut3DSurf[i].first); conn->pushBackSilent(cut3DSurf[i].second);
3924               connI->pushBackSilent(conn->getNumberOfTuples());
3925               cellIds2->pushBackSilent(i);
3926             }
3927           else
3928             {
3929               int cellId3DSurf=cut3DSurf[i].second;
3930               int offset=nodalI[cellId3DSurf]+1;
3931               int nbOfEdges=nodalI[cellId3DSurf+1]-offset;
3932               for(int j=0;j<nbOfEdges;j++)
3933                 {
3934                   conn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG2); conn->pushBackSilent(nodal[offset+j]); conn->pushBackSilent(nodal[offset+(j+1)%nbOfEdges]);
3935                   connI->pushBackSilent(conn->getNumberOfTuples());
3936                   cellIds2->pushBackSilent(cellId3DSurf);
3937                 }
3938             }
3939         }
3940     }
3941   if(cellIds2->empty())
3942     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3DSurf : No 3DSurf cells in this intercepts the specified plane !");
3943   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("Slice3DSurf",1);
3944   ret->setCoords(mDesc1->getCoords());
3945   ret->setConnectivity(conn,connI,true);
3946   cellIds=candidates->selectByTupleId(cellIds2->begin(),cellIds2->end());
3947   return ret.retn();
3948 }
3949
3950 /*!
3951  * Finds cells whose bounding boxes intersect a given plane.
3952  *  \param [in] origin - 3 components of a point defining location of the plane.
3953  *  \param [in] vec - 3 components of a vector normal to the plane. Vector magnitude
3954  *         must be greater than 1e-6.
3955  *  \param [in] eps - half-thickness of the plane.
3956  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of the found
3957  *         cells. The caller is to delete this array using decrRef() as it is no more
3958  *         needed.
3959  *  \throw If the coordinates array is not set.
3960  *  \throw If the nodal connectivity of cells is not defined.
3961  *  \throw If \a this->getSpaceDimension() != 3.
3962  *  \throw If magnitude of \a vec is less than 1e-6.
3963  *  \sa buildSlice3D()
3964  */
3965 DataArrayInt *MEDCouplingUMesh::getCellIdsCrossingPlane(const double *origin, const double *vec, double eps) const
3966 {
3967   checkFullyDefined();
3968   if(getSpaceDimension()!=3)
3969     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSlice3D works on umeshes with spaceDim equal to 3 !");
3970   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
3971   if(normm<1e-6)
3972     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellIdsCrossingPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
3973   double vec2[3];
3974   vec2[0]=vec[1]; vec2[1]=-vec[0]; vec2[2]=0.;//vec2 is the result of cross product of vec with (0,0,1)
3975   double angle=acos(vec[2]/normm);
3976   MCAuto<DataArrayInt> cellIds;
3977   double bbox[6];
3978   if(angle>eps)
3979     {
3980       MCAuto<DataArrayDouble> coo=_coords->deepCopy();
3981       double normm2(sqrt(vec2[0]*vec2[0]+vec2[1]*vec2[1]+vec2[2]*vec2[2]));
3982       if(normm2/normm>1e-6)
3983         MEDCouplingPointSet::Rotate3DAlg(origin,vec2,angle,coo->getNumberOfTuples(),coo->getPointer());
3984       MCAuto<MEDCouplingUMesh> mw=clone(false);//false -> shallow copy
3985       mw->setCoords(coo);
3986       mw->getBoundingBox(bbox);
3987       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3988       cellIds=mw->getCellsInBoundingBox(bbox,eps);
3989     }
3990   else
3991     {
3992       getBoundingBox(bbox);
3993       bbox[4]=origin[2]-eps; bbox[5]=origin[2]+eps;
3994       cellIds=getCellsInBoundingBox(bbox,eps);
3995     }
3996   return cellIds.retn();
3997 }
3998
3999 /*!
4000  * This method checks that \a this is a contiguous mesh. The user is expected to call this method on a mesh with meshdim==1.
4001  * If not an exception will thrown. If this is an empty mesh with no cell an exception will be thrown too.
4002  * No consideration of coordinate is done by this method.
4003  * 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)
4004  * If not false is returned. In case that false is returned a call to MEDCoupling::MEDCouplingUMesh::mergeNodes could be usefull.
4005  */
4006 bool MEDCouplingUMesh::isContiguous1D() const
4007 {
4008   if(getMeshDimension()!=1)
4009     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense only for 1D mesh !");
4010   int nbCells=getNumberOfCells();
4011   if(nbCells<1)
4012     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::isContiguous1D : this method has a sense for non empty mesh !");
4013   const int *connI=_nodal_connec_index->getConstPointer();
4014   const int *conn=_nodal_connec->getConstPointer();
4015   int ref=conn[connI[0]+2];
4016   for(int i=1;i<nbCells;i++)
4017     {
4018       if(conn[connI[i]+1]!=ref)
4019         return false;
4020       ref=conn[connI[i]+2];
4021     }
4022   return true;
4023 }
4024
4025 /*!
4026  * This method is only callable on mesh with meshdim == 1 containing only SEG2 and spaceDim==3.
4027  * This method projects this on the 3D line defined by (pt,v). This methods first checks that all SEG2 are along v vector.
4028  * \param pt reference point of the line
4029  * \param v normalized director vector of the line
4030  * \param eps max precision before throwing an exception
4031  * \param res output of size this->getNumberOfCells
4032  */
4033 void MEDCouplingUMesh::project1D(const double *pt, const double *v, double eps, double *res) const
4034 {
4035   if(getMeshDimension()!=1)
4036     throw INTERP_KERNEL::Exception("Expected a umesh with meshDim == 1 for project1D !");
4037   if(_types.size()!=1 || *(_types.begin())!=INTERP_KERNEL::NORM_SEG2)
4038     throw INTERP_KERNEL::Exception("Expected a umesh with only NORM_SEG2 type of elements for project1D !");
4039   if(getSpaceDimension()!=3)
4040     throw INTERP_KERNEL::Exception("Expected a umesh with spaceDim==3 for project1D !");
4041   MCAuto<MEDCouplingFieldDouble> f=buildDirectionVectorField();
4042   const double *fPtr=f->getArray()->getConstPointer();
4043   double tmp[3];
4044   for(int i=0;i<getNumberOfCells();i++)
4045     {
4046       const double *tmp1=fPtr+3*i;
4047       tmp[0]=tmp1[1]*v[2]-tmp1[2]*v[1];
4048       tmp[1]=tmp1[2]*v[0]-tmp1[0]*v[2];
4049       tmp[2]=tmp1[0]*v[1]-tmp1[1]*v[0];
4050       double n1=INTERP_KERNEL::norm<3>(tmp);
4051       n1/=INTERP_KERNEL::norm<3>(tmp1);
4052       if(n1>eps)
4053         throw INTERP_KERNEL::Exception("UMesh::Projection 1D failed !");
4054     }
4055   const double *coo=getCoords()->getConstPointer();
4056   for(int i=0;i<getNumberOfNodes();i++)
4057     {
4058       std::transform(coo+i*3,coo+i*3+3,pt,tmp,std::minus<double>());
4059       std::transform(tmp,tmp+3,v,tmp,std::multiplies<double>());
4060       res[i]=std::accumulate(tmp,tmp+3,0.);
4061     }
4062 }
4063
4064 /*!
4065  * 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. 
4066  * \a this is expected to be a mesh so that its space dimension is equal to its
4067  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4068  * 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).
4069  *
4070  * 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
4071  * 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).
4072  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4073  *
4074  * So this method is more accurate (so, more costly) than simply searching for the closest point in \a this.
4075  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4076  *
4077  * \param [in] ptBg the start pointer (included) of the coordinates of the point
4078  * \param [in] ptEnd the end pointer (not included) of the coordinates of the point
4079  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4080  * \return the positive value of the distance.
4081  * \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
4082  * dimension - 1.
4083  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoints
4084  */
4085 double MEDCouplingUMesh::distanceToPoint(const double *ptBg, const double *ptEnd, int& cellId) const
4086 {
4087   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4088   if(meshDim!=spaceDim-1)
4089     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint works only for spaceDim=meshDim+1 !");
4090   if(meshDim!=2 && meshDim!=1)
4091     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint : only mesh dimension 2 and 1 are implemented !");
4092   checkFullyDefined();
4093   if((int)std::distance(ptBg,ptEnd)!=spaceDim)
4094     { 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()); }
4095   DataArrayInt *ret1=0;
4096   MCAuto<DataArrayDouble> pts=DataArrayDouble::New(); pts->useArray(ptBg,false,C_DEALLOC,1,spaceDim);
4097   MCAuto<DataArrayDouble> ret0=distanceToPoints(pts,ret1);
4098   MCAuto<DataArrayInt> ret1Safe(ret1);
4099   cellId=*ret1Safe->begin();
4100   return *ret0->begin();
4101 }
4102
4103 /*!
4104  * This method computes the distance from each point of points serie \a pts (stored in a DataArrayDouble in which each tuple represents a point)
4105  *  to \a this  and the first \a cellId in \a this corresponding to the returned distance. 
4106  * 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
4107  * 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).
4108  * A user that needs to consider orphan nodes should invoke DataArrayDouble::minimalDistanceTo method on the coordinates array of \a this.
4109  * 
4110  * \a this is expected to be a mesh so that its space dimension is equal to its
4111  * mesh dimension + 1. Furthermore only mesh dimension 1 and 2 are supported for the moment.
4112  * 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).
4113  *
4114  * So this method is more accurate (so, more costly) than simply searching for each point in \a pts the closest point in \a this.
4115  * If only this information is enough for you simply call \c getCoords()->distanceToTuple on \a this.
4116  *
4117  * \param [in] pts the list of points in which each tuple represents a point
4118  * \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.
4119  * \return a newly allocated object to be dealed by the caller that tells for each point in \a pts the distance to \a this.
4120  * \throw if number of components of \a pts is not equal to the space dimension.
4121  * \throw if mesh dimension of \a this is not equal to space dimension - 1.
4122  * \sa DataArrayDouble::distanceToTuple, MEDCouplingUMesh::distanceToPoint
4123  */
4124 DataArrayDouble *MEDCouplingUMesh::distanceToPoints(const DataArrayDouble *pts, DataArrayInt *& cellIds) const
4125 {
4126   if(!pts)
4127     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : input points pointer is NULL !");
4128   pts->checkAllocated();
4129   int meshDim=getMeshDimension(),spaceDim=getSpaceDimension();
4130   if(meshDim!=spaceDim-1)
4131     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints works only for spaceDim=meshDim+1 !");
4132   if(meshDim!=2 && meshDim!=1)
4133     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only mesh dimension 2 and 1 are implemented !");
4134   if(pts->getNumberOfComponents()!=spaceDim)
4135     {
4136       std::ostringstream oss; oss << "MEDCouplingUMesh::distanceToPoints : input pts DataArrayDouble has " << pts->getNumberOfComponents() << " components whereas it should be equal to " << spaceDim << " (mesh spaceDimension) !";
4137       throw INTERP_KERNEL::Exception(oss.str().c_str());
4138     }
4139   checkFullyDefined();
4140   int nbCells=getNumberOfCells();
4141   if(nbCells==0)
4142     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : no cells in this !");
4143   int nbOfPts=pts->getNumberOfTuples();
4144   MCAuto<DataArrayDouble> ret0=DataArrayDouble::New(); ret0->alloc(nbOfPts,1);
4145   MCAuto<DataArrayInt> ret1=DataArrayInt::New(); ret1->alloc(nbOfPts,1);
4146   const int *nc=_nodal_connec->begin(),*ncI=_nodal_connec_index->begin(); const double *coords=_coords->begin();
4147   double *ret0Ptr=ret0->getPointer(); int *ret1Ptr=ret1->getPointer(); const double *ptsPtr=pts->begin();
4148   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree());
4149   const double *bbox(bboxArr->begin());
4150   switch(spaceDim)
4151   {
4152     case 3:
4153       {
4154         BBTreeDst<3> myTree(bbox,0,0,nbCells);
4155         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=3)
4156           {
4157             double x=std::numeric_limits<double>::max();
4158             std::vector<int> elems;
4159             myTree.getMinDistanceOfMax(ptsPtr,x);
4160             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4161             DistanceToPoint3DSurfAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4162           }
4163         break;
4164       }
4165     case 2:
4166       {
4167         BBTreeDst<2> myTree(bbox,0,0,nbCells);
4168         for(int i=0;i<nbOfPts;i++,ret0Ptr++,ret1Ptr++,ptsPtr+=2)
4169           {
4170             double x=std::numeric_limits<double>::max();
4171             std::vector<int> elems;
4172             myTree.getMinDistanceOfMax(ptsPtr,x);
4173             myTree.getElemsWhoseMinDistanceToPtSmallerThan(ptsPtr,x,elems);
4174             DistanceToPoint2DCurveAlg(ptsPtr,&elems[0],&elems[0]+elems.size(),coords,nc,ncI,*ret0Ptr,*ret1Ptr);
4175           }
4176         break;
4177       }
4178     default:
4179       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoints : only spacedim 2 and 3 supported !");
4180   }
4181   cellIds=ret1.retn();
4182   return ret0.retn();
4183 }
4184
4185 /// @cond INTERNAL
4186
4187 /*!
4188  * \param [in] pt the start pointer (included) of the coordinates of the point
4189  * \param [in] cellIdsBg the start pointer (included) of cellIds
4190  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4191  * \param [in] nc nodal connectivity
4192  * \param [in] ncI nodal connectivity index
4193  * \param [in,out] ret0 the min distance between \a this and the external input point
4194  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4195  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4196  */
4197 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)
4198 {
4199   cellId=-1;
4200   ret0=std::numeric_limits<double>::max();
4201   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4202     {
4203       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4204       {
4205         case INTERP_KERNEL::NORM_TRI3:
4206           {
4207             double tmp=INTERP_KERNEL::DistanceFromPtToTriInSpaceDim3(pt,coords+3*nc[ncI[*zeCell]+1],coords+3*nc[ncI[*zeCell]+2],coords+3*nc[ncI[*zeCell]+3]);
4208             if(tmp<ret0)
4209               { ret0=tmp; cellId=*zeCell; }
4210             break;
4211           }
4212         case INTERP_KERNEL::NORM_QUAD4:
4213         case INTERP_KERNEL::NORM_POLYGON:
4214           {
4215             double tmp=INTERP_KERNEL::DistanceFromPtToPolygonInSpaceDim3(pt,nc+ncI[*zeCell]+1,nc+ncI[*zeCell+1],coords);
4216             if(tmp<ret0)
4217               { ret0=tmp; cellId=*zeCell; }
4218             break;
4219           }
4220         default:
4221           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint3DSurfAlg : not managed cell type ! Supporting TRI3, QUAD4 and POLYGON !");
4222       }
4223     }
4224 }
4225
4226 /*!
4227  * \param [in] pt the start pointer (included) of the coordinates of the point
4228  * \param [in] cellIdsBg the start pointer (included) of cellIds
4229  * \param [in] cellIdsEnd the end pointer (excluded) of cellIds
4230  * \param [in] nc nodal connectivity
4231  * \param [in] ncI nodal connectivity index
4232  * \param [in,out] ret0 the min distance between \a this and the external input point
4233  * \param [out] cellId that corresponds to minimal distance. If the closer node is not linked to any cell in \a this -1 is returned.
4234  * \sa MEDCouplingUMesh::distanceToPoint, MEDCouplingUMesh::distanceToPoints
4235  */
4236 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)
4237 {
4238   cellId=-1;
4239   ret0=std::numeric_limits<double>::max();
4240   for(const int *zeCell=cellIdsBg;zeCell!=cellIdsEnd;zeCell++)
4241     {
4242       switch((INTERP_KERNEL::NormalizedCellType)nc[ncI[*zeCell]])
4243       {
4244         case INTERP_KERNEL::NORM_SEG2:
4245           {
4246             std::size_t uselessEntry=0;
4247             double tmp=INTERP_KERNEL::SquareDistanceFromPtToSegInSpaceDim2(pt,coords+2*nc[ncI[*zeCell]+1],coords+2*nc[ncI[*zeCell]+2],uselessEntry);
4248             tmp=sqrt(tmp);
4249             if(tmp<ret0)
4250               { ret0=tmp; cellId=*zeCell; }
4251             break;
4252           }
4253         default:
4254           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::distanceToPoint2DCurveAlg : not managed cell type ! Supporting SEG2 !");
4255       }
4256     }
4257 }
4258 /// @endcond
4259
4260 /*!
4261  * Finds cells in contact with a ball (i.e. a point with precision). 
4262  * 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.
4263  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4264  *
4265  * \warning This method is suitable if the caller intends to evaluate only one
4266  *          point, for more points getCellsContainingPoints() is recommended as it is
4267  *          faster. 
4268  *  \param [in] pos - array of coordinates of the ball central point.
4269  *  \param [in] eps - ball radius.
4270  *  \return int - a smallest id of cells being in contact with the ball, -1 in case
4271  *         if there are no such cells.
4272  *  \throw If the coordinates array is not set.
4273  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4274  */
4275 int MEDCouplingUMesh::getCellContainingPoint(const double *pos, double eps) const
4276 {
4277   std::vector<int> elts;
4278   getCellsContainingPoint(pos,eps,elts);
4279   if(elts.empty())
4280     return -1;
4281   return elts.front();
4282 }
4283
4284 /*!
4285  * Finds cells in contact with a ball (i.e. a point with precision).
4286  * 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.
4287  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4288  * \warning This method is suitable if the caller intends to evaluate only one
4289  *          point, for more points getCellsContainingPoints() is recommended as it is
4290  *          faster. 
4291  *  \param [in] pos - array of coordinates of the ball central point.
4292  *  \param [in] eps - ball radius.
4293  *  \param [out] elts - vector returning ids of the found cells. It is cleared
4294  *         before inserting ids.
4295  *  \throw If the coordinates array is not set.
4296  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4297  *
4298  *  \if ENABLE_EXAMPLES
4299  *  \ref cpp_mcumesh_getCellsContainingPoint "Here is a C++ example".<br>
4300  *  \ref  py_mcumesh_getCellsContainingPoint "Here is a Python example".
4301  *  \endif
4302  */
4303 void MEDCouplingUMesh::getCellsContainingPoint(const double *pos, double eps, std::vector<int>& elts) const
4304 {
4305   MCAuto<DataArrayInt> eltsUg,eltsIndexUg;
4306   getCellsContainingPoints(pos,1,eps,eltsUg,eltsIndexUg);
4307   elts.clear(); elts.insert(elts.end(),eltsUg->begin(),eltsUg->end());
4308 }
4309
4310 /// @cond INTERNAL
4311
4312 namespace MEDCoupling
4313 {
4314   template<const int SPACEDIMM>
4315   class DummyClsMCUG
4316   {
4317   public:
4318     static const int MY_SPACEDIM=SPACEDIMM;
4319     static const int MY_MESHDIM=8;
4320     typedef int MyConnType;
4321     static const INTERP_KERNEL::NumberingPolicy My_numPol=INTERP_KERNEL::ALL_C_MODE;
4322     // begin
4323     // useless, but for windows compilation ...
4324     const double* getCoordinatesPtr() const { return 0; }
4325     const int* getConnectivityPtr() const { return 0; }
4326     const int* getConnectivityIndexPtr() const { return 0; }
4327     INTERP_KERNEL::NormalizedCellType getTypeOfElement(int) const { return (INTERP_KERNEL::NormalizedCellType)0; }
4328     // end
4329   };
4330
4331   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge2(INTERP_KERNEL::NormalizedCellType typ, const int *bg, const double *coords2D, std::map< MCAuto<INTERP_KERNEL::Node>,int>& m)
4332   {
4333     INTERP_KERNEL::Edge *ret(0);
4334     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]));
4335     m[n0]=bg[0]; m[n1]=bg[1];
4336     switch(typ)
4337     {
4338       case INTERP_KERNEL::NORM_SEG2:
4339         {
4340           ret=new INTERP_KERNEL::EdgeLin(n0,n1);
4341           break;
4342         }
4343       case INTERP_KERNEL::NORM_SEG3:
4344         {
4345           INTERP_KERNEL::Node *n2(new INTERP_KERNEL::Node(coords2D[2*bg[2]],coords2D[2*bg[2]+1])); m[n2]=bg[2];
4346           INTERP_KERNEL::EdgeLin *e1(new INTERP_KERNEL::EdgeLin(n0,n2)),*e2(new INTERP_KERNEL::EdgeLin(n2,n1));
4347           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4348           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4349           bool colinearity(inters.areColinears());
4350           delete e1; delete e2;
4351           if(colinearity)
4352             { ret=new INTERP_KERNEL::EdgeLin(n0,n1); }
4353           else
4354             { ret=new INTERP_KERNEL::EdgeArcCircle(n0,n2,n1); }
4355           break;
4356         }
4357       default:
4358         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge2 : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4359     }
4360     return ret;
4361   }
4362
4363   INTERP_KERNEL::Edge *MEDCouplingUMeshBuildQPFromEdge(INTERP_KERNEL::NormalizedCellType typ, std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >& mapp2, const int *bg)
4364   {
4365     INTERP_KERNEL::Edge *ret=0;
4366     switch(typ)
4367     {
4368       case INTERP_KERNEL::NORM_SEG2:
4369         {
4370           ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4371           break;
4372         }
4373       case INTERP_KERNEL::NORM_SEG3:
4374         {
4375           INTERP_KERNEL::EdgeLin *e1=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[2]].first);
4376           INTERP_KERNEL::EdgeLin *e2=new INTERP_KERNEL::EdgeLin(mapp2[bg[2]].first,mapp2[bg[1]].first);
4377           INTERP_KERNEL::SegSegIntersector inters(*e1,*e2);
4378           // is the SEG3 degenerated, and thus can be reduced to a SEG2?
4379           bool colinearity=inters.areColinears();
4380           delete e1; delete e2;
4381           if(colinearity)
4382             ret=new INTERP_KERNEL::EdgeLin(mapp2[bg[0]].first,mapp2[bg[1]].first);
4383           else
4384             ret=new INTERP_KERNEL::EdgeArcCircle(mapp2[bg[0]].first,mapp2[bg[2]].first,mapp2[bg[1]].first);
4385           mapp2[bg[2]].second=false;
4386           break;
4387         }
4388       default:
4389         throw INTERP_KERNEL::Exception("MEDCouplingUMeshBuildQPFromEdge : Expecting a mesh with spaceDim==2 and meshDim==1 !");
4390     }
4391     return ret;
4392   }
4393
4394   /*!
4395    * This method creates a sub mesh in Geometric2D DS. The sub mesh is composed by the sub set of cells in 'candidates' taken from
4396    * the global mesh 'mDesc'.
4397    * The input mesh 'mDesc' must be so that mDim==1 and spaceDim==2.
4398    * 'mapp' returns a mapping between local numbering in submesh (represented by a Node*) and the global node numbering in 'mDesc'.
4399    */
4400   INTERP_KERNEL::QuadraticPolygon *MEDCouplingUMeshBuildQPFromMesh(const MEDCouplingUMesh *mDesc, const std::vector<int>& candidates,
4401                                                                    std::map<INTERP_KERNEL::Node *,int>& mapp)
4402   {
4403     mapp.clear();
4404     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.
4405     const double *coo=mDesc->getCoords()->getConstPointer();
4406     const int *c=mDesc->getNodalConnectivity()->getConstPointer();
4407     const int *cI=mDesc->getNodalConnectivityIndex()->getConstPointer();
4408     std::set<int> s;
4409     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4410       s.insert(c+cI[*it]+1,c+cI[(*it)+1]);
4411     for(std::set<int>::const_iterator it2=s.begin();it2!=s.end();it2++)
4412       {
4413         INTERP_KERNEL::Node *n=new INTERP_KERNEL::Node(coo[2*(*it2)],coo[2*(*it2)+1]);
4414         mapp2[*it2]=std::pair<INTERP_KERNEL::Node *,bool>(n,true);
4415       }
4416     INTERP_KERNEL::QuadraticPolygon *ret=new INTERP_KERNEL::QuadraticPolygon;
4417     for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
4418       {
4419         INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[*it]];
4420         ret->pushBack(MEDCouplingUMeshBuildQPFromEdge(typ,mapp2,c+cI[*it]+1));
4421       }
4422     for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it2=mapp2.begin();it2!=mapp2.end();it2++)
4423       {
4424         if((*it2).second.second)
4425           mapp[(*it2).second.first]=(*it2).first;
4426         ((*it2).second.first)->decrRef();
4427       }
4428     return ret;
4429   }
4430
4431   INTERP_KERNEL::Node *MEDCouplingUMeshBuildQPNode(int nodeId, const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo)
4432   {
4433     if(nodeId>=offset2)
4434       {
4435         int locId=nodeId-offset2;
4436         return new INTERP_KERNEL::Node(addCoo[2*locId],addCoo[2*locId+1]);
4437       }
4438     if(nodeId>=offset1)
4439       {
4440         int locId=nodeId-offset1;
4441         return new INTERP_KERNEL::Node(coo2[2*locId],coo2[2*locId+1]);
4442       }
4443     return new INTERP_KERNEL::Node(coo1[2*nodeId],coo1[2*nodeId+1]);
4444   }
4445
4446   /**
4447    * Construct a mapping between set of Nodes and the standart MEDCoupling connectivity format (c, cI).
4448    */
4449   void MEDCouplingUMeshBuildQPFromMesh3(const double *coo1, int offset1, const double *coo2, int offset2, const std::vector<double>& addCoo,
4450                                         const int *desc1Bg, const int *desc1End, const std::vector<std::vector<int> >& intesctEdges1,
4451                                         /*output*/std::map<INTERP_KERNEL::Node *,int>& mapp, std::map<int,INTERP_KERNEL::Node *>& mappRev)
4452   {
4453     for(const int *desc1=desc1Bg;desc1!=desc1End;desc1++)
4454       {
4455         int eltId1=abs(*desc1)-1;
4456         for(std::vector<int>::const_iterator it1=intesctEdges1[eltId1].begin();it1!=intesctEdges1[eltId1].end();it1++)
4457           {
4458             std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.find(*it1);
4459             if(it==mappRev.end())
4460               {
4461                 INTERP_KERNEL::Node *node=MEDCouplingUMeshBuildQPNode(*it1,coo1,offset1,coo2,offset2,addCoo);
4462                 mapp[node]=*it1;
4463                 mappRev[*it1]=node;
4464               }
4465           }
4466       }
4467   }
4468 }
4469
4470 /// @endcond
4471
4472 template<int SPACEDIM>
4473 void MEDCouplingUMesh::getCellsContainingPointsAlg(const double *coords, const double *pos, int nbOfPoints,
4474                                                    double eps, MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4475 {
4476   elts=DataArrayInt::New(); eltsIndex=DataArrayInt::New(); eltsIndex->alloc(nbOfPoints+1,1); eltsIndex->setIJ(0,0,0); elts->alloc(0,1);
4477   int *eltsIndexPtr(eltsIndex->getPointer());
4478   MCAuto<DataArrayDouble> bboxArr(getBoundingBoxForBBTree(eps));
4479   const double *bbox(bboxArr->begin());
4480   int nbOfCells=getNumberOfCells();
4481   const int *conn=_nodal_connec->getConstPointer();
4482   const int *connI=_nodal_connec_index->getConstPointer();
4483   double bb[2*SPACEDIM];
4484   BBTree<SPACEDIM,int> myTree(&bbox[0],0,0,nbOfCells,-eps);
4485   for(int i=0;i<nbOfPoints;i++)
4486     {
4487       eltsIndexPtr[i+1]=eltsIndexPtr[i];
4488       for(int j=0;j<SPACEDIM;j++)
4489         {
4490           bb[2*j]=pos[SPACEDIM*i+j];
4491           bb[2*j+1]=pos[SPACEDIM*i+j];
4492         }
4493       std::vector<int> candidates;
4494       myTree.getIntersectingElems(bb,candidates);
4495       for(std::vector<int>::const_iterator iter=candidates.begin();iter!=candidates.end();iter++)
4496         {
4497           int sz(connI[(*iter)+1]-connI[*iter]-1);
4498           INTERP_KERNEL::NormalizedCellType ct((INTERP_KERNEL::NormalizedCellType)conn[connI[*iter]]);
4499           bool status(false);
4500           if(ct!=INTERP_KERNEL::NORM_POLYGON && ct!=INTERP_KERNEL::NORM_QPOLYG)
4501             status=INTERP_KERNEL::PointLocatorAlgos<DummyClsMCUG<SPACEDIM> >::isElementContainsPoint(pos+i*SPACEDIM,ct,coords,conn+connI[*iter]+1,sz,eps);
4502           else
4503             {
4504               if(SPACEDIM!=2)
4505                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPointsAlg : not implemented yet for POLYGON and QPOLYGON in spaceDim 3 !");
4506               INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
4507               INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
4508               std::vector<INTERP_KERNEL::Node *> nodes(sz);
4509               INTERP_KERNEL::QuadraticPolygon *pol(0);
4510               for(int j=0;j<sz;j++)
4511                 {
4512                   int nodeId(conn[connI[*iter]+1+j]);
4513                   nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*SPACEDIM],coords[nodeId*SPACEDIM+1]);
4514                 }
4515               if(!INTERP_KERNEL::CellModel::GetCellModel(ct).isQuadratic())
4516                 pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
4517               else
4518                 pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
4519               INTERP_KERNEL::Node *n(new INTERP_KERNEL::Node(pos[i*SPACEDIM],pos[i*SPACEDIM+1]));
4520               double a(0.),b(0.),c(0.);
4521               a=pol->normalizeMe(b,c); n->applySimilarity(b,c,a);
4522               status=pol->isInOrOut2(n);
4523               delete pol; n->decrRef();
4524             }
4525           if(status)
4526             {
4527               eltsIndexPtr[i+1]++;
4528               elts->pushBackSilent(*iter);
4529             }
4530         }
4531     }
4532 }
4533 /*!
4534  * Finds cells in contact with several balls (i.e. points with precision).
4535  * This method is an extension of getCellContainingPoint() and
4536  * getCellsContainingPoint() for the case of multiple points.
4537  * 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.
4538  * If it is not the case, please change their types to INTERP_KERNEL::NORM_POLYGON or INTERP_KERNEL::NORM_QPOLYG before invoking this method.
4539  *  \param [in] pos - an array of coordinates of points in full interlace mode :
4540  *         X0,Y0,Z0,X1,Y1,Z1,... Size of the array must be \a
4541  *         this->getSpaceDimension() * \a nbOfPoints 
4542  *  \param [in] nbOfPoints - number of points to locate within \a this mesh.
4543  *  \param [in] eps - radius of balls (i.e. the precision).
4544  *  \param [out] elts - vector returning ids of found cells.
4545  *  \param [out] eltsIndex - an array, of length \a nbOfPoints + 1,
4546  *         dividing cell ids in \a elts into groups each referring to one
4547  *         point. Its every element (except the last one) is an index pointing to the
4548  *         first id of a group of cells. For example cells in contact with the *i*-th
4549  *         point are described by following range of indices:
4550  *         [ \a eltsIndex[ *i* ], \a eltsIndex[ *i*+1 ] ) and the cell ids are
4551  *         \a elts[ \a eltsIndex[ *i* ]], \a elts[ \a eltsIndex[ *i* ] + 1 ], ...
4552  *         Number of cells in contact with the *i*-th point is
4553  *         \a eltsIndex[ *i*+1 ] - \a eltsIndex[ *i* ].
4554  *  \throw If the coordinates array is not set.
4555  *  \throw If \a this->getMeshDimension() != \a this->getSpaceDimension().
4556  *
4557  *  \if ENABLE_EXAMPLES
4558  *  \ref cpp_mcumesh_getCellsContainingPoints "Here is a C++ example".<br>
4559  *  \ref  py_mcumesh_getCellsContainingPoints "Here is a Python example".
4560  *  \endif
4561  */
4562 void MEDCouplingUMesh::getCellsContainingPoints(const double *pos, int nbOfPoints, double eps,
4563                                                 MCAuto<DataArrayInt>& elts, MCAuto<DataArrayInt>& eltsIndex) const
4564 {
4565   int spaceDim=getSpaceDimension();
4566   int mDim=getMeshDimension();
4567   if(spaceDim==3)
4568     {
4569       if(mDim==3)
4570         {
4571           const double *coords=_coords->getConstPointer();
4572           getCellsContainingPointsAlg<3>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4573         }
4574       /*else if(mDim==2)
4575         {
4576
4577         }*/
4578       else
4579         throw INTERP_KERNEL::Exception("For spaceDim==3 only meshDim==3 implemented for getelementscontainingpoints !");
4580     }
4581   else if(spaceDim==2)
4582     {
4583       if(mDim==2)
4584         {
4585           const double *coords=_coords->getConstPointer();
4586           getCellsContainingPointsAlg<2>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4587         }
4588       else
4589         throw INTERP_KERNEL::Exception("For spaceDim==2 only meshDim==2 implemented for getelementscontainingpoints !");
4590     }
4591   else if(spaceDim==1)
4592     {
4593       if(mDim==1)
4594         {
4595           const double *coords=_coords->getConstPointer();
4596           getCellsContainingPointsAlg<1>(coords,pos,nbOfPoints,eps,elts,eltsIndex);
4597         }
4598       else
4599         throw INTERP_KERNEL::Exception("For spaceDim==1 only meshDim==1 implemented for getelementscontainingpoints !");
4600     }
4601   else
4602     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getCellsContainingPoints : not managed for mdim not in [1,2,3] !");
4603 }
4604
4605 /*!
4606  * Finds butterfly cells in \a this mesh. A 2D cell is considered to be butterfly if at
4607  * least two its edges intersect each other anywhere except their extremities. An
4608  * INTERP_KERNEL::NORM_NORI3 cell can \b not be butterfly.
4609  *  \param [in,out] cells - a vector returning ids of the found cells. It is not
4610  *         cleared before filling in.
4611  *  \param [in] eps - precision.
4612  *  \throw If \a this->getMeshDimension() != 2.
4613  *  \throw If \a this->getSpaceDimension() != 2 && \a this->getSpaceDimension() != 3.
4614  */
4615 void MEDCouplingUMesh::checkButterflyCells(std::vector<int>& cells, double eps) const
4616 {
4617   const char msg[]="Butterfly detection work only for 2D cells with spaceDim==2 or 3!";
4618   if(getMeshDimension()!=2)
4619     throw INTERP_KERNEL::Exception(msg);
4620   int spaceDim=getSpaceDimension();
4621   if(spaceDim!=2 && spaceDim!=3)
4622     throw INTERP_KERNEL::Exception(msg);
4623   const int *conn=_nodal_connec->getConstPointer();
4624   const int *connI=_nodal_connec_index->getConstPointer();
4625   int nbOfCells=getNumberOfCells();
4626   std::vector<double> cell2DinS2;
4627   for(int i=0;i<nbOfCells;i++)
4628     {
4629       int offset=connI[i];
4630       int nbOfNodesForCell=connI[i+1]-offset-1;
4631       if(nbOfNodesForCell<=3)
4632         continue;
4633       bool isQuad=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[offset]).isQuadratic();
4634       project2DCellOnXY(conn+offset+1,conn+connI[i+1],cell2DinS2);
4635       if(isButterfly2DCell(cell2DinS2,isQuad,eps))
4636         cells.push_back(i);
4637       cell2DinS2.clear();
4638     }
4639 }
4640
4641 /*!
4642  * This method is typically requested to unbutterfly 2D linear cells in \b this.
4643  *
4644  * 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.
4645  * 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.
4646  * 
4647  * For each 2D linear cell in \b this, this method builds the convex envelop (or the convex hull) of the current cell.
4648  * This convex envelop is computed using Jarvis march algorithm.
4649  * The coordinates and the number of cells of \b this remain unchanged on invocation of this method.
4650  * 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)
4651  * 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.
4652  *
4653  * \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.
4654  * \sa MEDCouplingUMesh::colinearize2D
4655  */
4656 DataArrayInt *MEDCouplingUMesh::convexEnvelop2D()
4657 {
4658   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
4659     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convexEnvelop2D  works only for meshDim=2 and spaceDim=2 !");
4660   checkFullyDefined();
4661   const double *coords=getCoords()->getConstPointer();
4662   int nbOfCells=getNumberOfCells();
4663   MCAuto<DataArrayInt> nodalConnecIndexOut=DataArrayInt::New();
4664   nodalConnecIndexOut->alloc(nbOfCells+1,1);
4665   MCAuto<DataArrayInt> nodalConnecOut(DataArrayInt::New());
4666   int *workIndexOut=nodalConnecIndexOut->getPointer();
4667   *workIndexOut=0;
4668   const int *nodalConnecIn=_nodal_connec->getConstPointer();
4669   const int *nodalConnecIndexIn=_nodal_connec_index->getConstPointer();
4670   std::set<INTERP_KERNEL::NormalizedCellType> types;
4671   MCAuto<DataArrayInt> isChanged(DataArrayInt::New());
4672   isChanged->alloc(0,1);
4673   for(int i=0;i<nbOfCells;i++,workIndexOut++)
4674     {
4675       int pos=nodalConnecOut->getNumberOfTuples();
4676       if(BuildConvexEnvelopOf2DCellJarvis(coords,nodalConnecIn+nodalConnecIndexIn[i],nodalConnecIn+nodalConnecIndexIn[i+1],nodalConnecOut))
4677         isChanged->pushBackSilent(i);
4678       types.insert((INTERP_KERNEL::NormalizedCellType)nodalConnecOut->getIJ(pos,0));
4679       workIndexOut[1]=nodalConnecOut->getNumberOfTuples();
4680     }
4681   if(isChanged->empty())
4682     return 0;
4683   setConnectivity(nodalConnecOut,nodalConnecIndexOut,false);
4684   _types=types;
4685   return isChanged.retn();
4686 }
4687
4688 /*!
4689  * This method is \b NOT const because it can modify \a this.
4690  * \a this is expected to be an unstructured mesh with meshDim==2 and spaceDim==3. If not an exception will be thrown.
4691  * \param mesh1D is an unstructured mesh with MeshDim==1 and spaceDim==3. If not an exception will be thrown.
4692  * \param policy specifies the type of extrusion chosen:
4693  *   - \b 0 for translation only (most simple): the cells of the 1D mesh represent the vectors along which the 2D mesh
4694  *   will be repeated to build each level
4695  *   - \b 1 for translation and rotation: the translation is done as above. For each level, an arc of circle is fitted on
4696  *   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
4697  *   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
4698  *   arc.
4699  * \return an unstructured mesh with meshDim==3 and spaceDim==3. The returned mesh has the same coords than \a this.  
4700  */
4701 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMesh(const MEDCouplingUMesh *mesh1D, int policy)
4702 {
4703   checkFullyDefined();
4704   mesh1D->checkFullyDefined();
4705   if(!mesh1D->isContiguous1D())
4706     throw INTERP_KERNEL::Exception("buildExtrudedMesh : 1D mesh passed in parameter is not contiguous !");
4707   if(getSpaceDimension()!=mesh1D->getSpaceDimension())
4708     throw INTERP_KERNEL::Exception("Invalid call to buildExtrudedMesh this and mesh1D must have same space dimension !");
4709   if((getMeshDimension()!=2 || getSpaceDimension()!=3) && (getMeshDimension()!=1 || getSpaceDimension()!=2))
4710     throw INTERP_KERNEL::Exception("Invalid 'this' for buildExtrudedMesh method : must be (meshDim==2 and spaceDim==3) or (meshDim==1 and spaceDim==2) !");
4711   if(mesh1D->getMeshDimension()!=1)
4712     throw INTERP_KERNEL::Exception("Invalid 'mesh1D' for buildExtrudedMesh method : must be meshDim==1 !");
4713   bool isQuad=false;
4714   if(isPresenceOfQuadratic())
4715     {
4716       if(mesh1D->isFullyQuadratic())
4717         isQuad=true;
4718       else
4719         throw INTERP_KERNEL::Exception("Invalid 2D mesh and 1D mesh because 2D mesh has quadratic cells and 1D is not fully quadratic !");
4720     }
4721   int oldNbOfNodes(getNumberOfNodes());
4722   MCAuto<DataArrayDouble> newCoords;
4723   switch(policy)
4724   {
4725     case 0:
4726       {
4727         newCoords=fillExtCoordsUsingTranslation(mesh1D,isQuad);
4728         break;
4729       }
4730     case 1:
4731       {
4732         newCoords=fillExtCoordsUsingTranslAndAutoRotation(mesh1D,isQuad);
4733         break;
4734       }
4735     default:
4736       throw INTERP_KERNEL::Exception("Not implemented extrusion policy : must be in (0) !");
4737   }
4738   setCoords(newCoords);
4739   MCAuto<MEDCouplingUMesh> ret(buildExtrudedMeshFromThisLowLev(oldNbOfNodes,isQuad));
4740   updateTime();
4741   return ret.retn();
4742 }
4743
4744 /*!
4745  * This method works on a 3D curve linear mesh that is to say (meshDim==1 and spaceDim==3).
4746  * If it is not the case an exception will be thrown.
4747  * This method is non const because the coordinate of \a this can be appended with some new points issued from
4748  * intersection of plane defined by ('origin','vec').
4749  * This method has one in/out parameter : 'cut3DCurve'.
4750  * Param 'cut3DCurve' is expected to be of size 'this->getNumberOfCells()'. For each i in [0,'this->getNumberOfCells()')
4751  * if cut3DCurve[i]==-2, it means that for cell #i in \a this nothing has been detected previously.
4752  * if cut3DCurve[i]==-1, it means that cell#i has been already detected to be fully part of plane defined by ('origin','vec').
4753  * This method will throw an exception if \a this contains a non linear segment.
4754  */
4755 void MEDCouplingUMesh::split3DCurveWithPlane(const double *origin, const double *vec, double eps, std::vector<int>& cut3DCurve)
4756 {
4757   checkFullyDefined();
4758   if(getMeshDimension()!=1 || getSpaceDimension()!=3)
4759     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane works on umeshes with meshdim equal to 1 and spaceDim equal to 3 !");
4760   int ncells=getNumberOfCells();
4761   int nnodes=getNumberOfNodes();
4762   double vec2[3],vec3[3],vec4[3];
4763   double normm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
4764   if(normm<1e-6)
4765     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : parameter 'vec' should have a norm2 greater than 1e-6 !");
4766   vec2[0]=vec[0]/normm; vec2[1]=vec[1]/normm; vec2[2]=vec[2]/normm;
4767   const int *conn=_nodal_connec->getConstPointer();
4768   const int *connI=_nodal_connec_index->getConstPointer();
4769   const double *coo=_coords->getConstPointer();
4770   std::vector<double> addCoo;
4771   for(int i=0;i<ncells;i++)
4772     {
4773       if(conn[connI[i]]==(int)INTERP_KERNEL::NORM_SEG2)
4774         {
4775           if(cut3DCurve[i]==-2)
4776             {
4777               int st=conn[connI[i]+1],endd=conn[connI[i]+2];
4778               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];
4779               double normm2=sqrt(vec3[0]*vec3[0]+vec3[1]*vec3[1]+vec3[2]*vec3[2]);
4780               double colin=std::abs((vec3[0]*vec2[0]+vec3[1]*vec2[1]+vec3[2]*vec2[2])/normm2);
4781               if(colin>eps)//if colin<=eps -> current SEG2 is colinear to the input plane
4782                 {
4783                   const double *st2=coo+3*st;
4784                   vec4[0]=st2[0]-origin[0]; vec4[1]=st2[1]-origin[1]; vec4[2]=st2[2]-origin[2];
4785                   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]));
4786                   if(pos>eps && pos<1-eps)
4787                     {
4788                       int nNode=((int)addCoo.size())/3;
4789                       vec4[0]=st2[0]+pos*vec3[0]; vec4[1]=st2[1]+pos*vec3[1]; vec4[2]=st2[2]+pos*vec3[2];
4790                       addCoo.insert(addCoo.end(),vec4,vec4+3);
4791                       cut3DCurve[i]=nnodes+nNode;
4792                     }
4793                 }
4794             }
4795         }
4796       else
4797         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split3DCurveWithPlane : this method is only available for linear cell (NORM_SEG2) !");
4798     }
4799   if(!addCoo.empty())
4800     {
4801       int newNbOfNodes=nnodes+((int)addCoo.size())/3;
4802       MCAuto<DataArrayDouble> coo2=DataArrayDouble::New();
4803       coo2->alloc(newNbOfNodes,3);
4804       double *tmp=coo2->getPointer();
4805       tmp=std::copy(_coords->begin(),_coords->end(),tmp);
4806       std::copy(addCoo.begin(),addCoo.end(),tmp);
4807       DataArrayDouble::SetArrayIn(coo2,_coords);
4808     }
4809 }
4810
4811 /*!
4812  * This method incarnates the policy 0 for MEDCouplingUMesh::buildExtrudedMesh method.
4813  * \param mesh1D is the input 1D mesh used for translation computation.
4814  * \return newCoords new coords filled by this method. 
4815  */
4816 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4817 {
4818   int oldNbOfNodes=getNumberOfNodes();
4819   int nbOf1DCells=mesh1D->getNumberOfCells();
4820   int spaceDim=getSpaceDimension();
4821   DataArrayDouble *ret=DataArrayDouble::New();
4822   std::vector<bool> isQuads;
4823   int nbOfLevsInVec=isQuad?2*nbOf1DCells+1:nbOf1DCells+1;
4824   ret->alloc(oldNbOfNodes*nbOfLevsInVec,spaceDim);
4825   double *retPtr=ret->getPointer();
4826   const double *coords=getCoords()->getConstPointer();
4827   double *work=std::copy(coords,coords+spaceDim*oldNbOfNodes,retPtr);
4828   std::vector<int> v;
4829   std::vector<double> c;
4830   double vec[3];
4831   v.reserve(3);
4832   c.reserve(6);
4833   for(int i=0;i<nbOf1DCells;i++)
4834     {
4835       v.resize(0);
4836       mesh1D->getNodeIdsOfCell(i,v);
4837       c.resize(0);
4838       mesh1D->getCoordinatesOfNode(v[isQuad?2:1],c);
4839       mesh1D->getCoordinatesOfNode(v[0],c);
4840       std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4841       for(int j=0;j<oldNbOfNodes;j++)
4842         work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4843       if(isQuad)
4844         {
4845           c.resize(0);
4846           mesh1D->getCoordinatesOfNode(v[1],c);
4847           mesh1D->getCoordinatesOfNode(v[0],c);
4848           std::transform(c.begin(),c.begin()+spaceDim,c.begin()+spaceDim,vec,std::minus<double>());
4849           for(int j=0;j<oldNbOfNodes;j++)
4850             work=std::transform(vec,vec+spaceDim,retPtr+spaceDim*(i*oldNbOfNodes+j),work,std::plus<double>());
4851         }
4852     }
4853   ret->copyStringInfoFrom(*getCoords());
4854   return ret;
4855 }
4856
4857 /*!
4858  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4859  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4860  * \return newCoords new coords filled by this method. 
4861  */
4862 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4863 {
4864   if(mesh1D->getSpaceDimension()==2)
4865     return fillExtCoordsUsingTranslAndAutoRotation2D(mesh1D,isQuad);
4866   if(mesh1D->getSpaceDimension()==3)
4867     return fillExtCoordsUsingTranslAndAutoRotation3D(mesh1D,isQuad);
4868   throw INTERP_KERNEL::Exception("Not implemented rotation and translation alg. for spacedim other than 2 and 3 !");
4869 }
4870
4871 /*!
4872  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4873  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4874  * \return newCoords new coords filled by this method. 
4875  */
4876 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4877 {
4878   if(isQuad)
4879     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : not implemented for quadratic cells !");
4880   int oldNbOfNodes=getNumberOfNodes();
4881   int nbOf1DCells=mesh1D->getNumberOfCells();
4882   if(nbOf1DCells<2)
4883     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation2D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4884   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4885   int nbOfLevsInVec=nbOf1DCells+1;
4886   ret->alloc(oldNbOfNodes*nbOfLevsInVec,2);
4887   double *retPtr=ret->getPointer();
4888   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4889   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4890   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4891   tmp->setCoords(tmp2);
4892   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4893   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4894   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4895   for(int i=1;i<nbOfLevsInVec;i++)
4896     {
4897       const double *begin=coo1D+2*conn1D[connI1D[i-1]+1];
4898       const double *end=coo1D+2*conn1D[connI1D[i-1]+2];
4899       const double *third=i+1<nbOfLevsInVec?coo1D+2*conn1D[connI1D[i]+2]:coo1D+2*conn1D[connI1D[i-2]+1];
4900       const double vec[2]={end[0]-begin[0],end[1]-begin[1]};
4901       tmp->translate(vec);
4902       double tmp3[2],radius,alpha,alpha0;
4903       const double *p0=i+1<nbOfLevsInVec?begin:third;
4904       const double *p1=i+1<nbOfLevsInVec?end:begin;
4905       const double *p2=i+1<nbOfLevsInVec?third:end;
4906       INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0,p1,p2,tmp3,radius,alpha,alpha0);
4907       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]);
4908       double angle=acos(cosangle/(radius*radius));
4909       tmp->rotate(end,0,angle);
4910       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4911     }
4912   return ret.retn();
4913 }
4914
4915 /*!
4916  * This method incarnates the policy 1 for MEDCouplingUMesh::buildExtrudedMesh method.
4917  * \param mesh1D is the input 1D mesh used for translation and automatic rotation computation.
4918  * \return newCoords new coords filled by this method. 
4919  */
4920 DataArrayDouble *MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D(const MEDCouplingUMesh *mesh1D, bool isQuad) const
4921 {
4922   if(isQuad)
4923     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : not implemented for quadratic cells !");
4924   int oldNbOfNodes=getNumberOfNodes();
4925   int nbOf1DCells=mesh1D->getNumberOfCells();
4926   if(nbOf1DCells<2)
4927     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::fillExtCoordsUsingTranslAndAutoRotation3D : impossible to detect any angle of rotation ! Change extrusion policy 1->0 !");
4928   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
4929   int nbOfLevsInVec=nbOf1DCells+1;
4930   ret->alloc(oldNbOfNodes*nbOfLevsInVec,3);
4931   double *retPtr=ret->getPointer();
4932   retPtr=std::copy(getCoords()->getConstPointer(),getCoords()->getConstPointer()+getCoords()->getNbOfElems(),retPtr);
4933   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
4934   MCAuto<DataArrayDouble> tmp2=getCoords()->deepCopy();
4935   tmp->setCoords(tmp2);
4936   const double *coo1D=mesh1D->getCoords()->getConstPointer();
4937   const int *conn1D=mesh1D->getNodalConnectivity()->getConstPointer();
4938   const int *connI1D=mesh1D->getNodalConnectivityIndex()->getConstPointer();
4939   for(int i=1;i<nbOfLevsInVec;i++)
4940     {
4941       const double *begin=coo1D+3*conn1D[connI1D[i-1]+1];
4942       const double *end=coo1D+3*conn1D[connI1D[i-1]+2];
4943       const double *third=i+1<nbOfLevsInVec?coo1D+3*conn1D[connI1D[i]+2]:coo1D+3*conn1D[connI1D[i-2]+1];
4944       const double vec[3]={end[0]-begin[0],end[1]-begin[1],end[2]-begin[2]};
4945       tmp->translate(vec);
4946       double tmp3[2],radius,alpha,alpha0;
4947       const double *p0=i+1<nbOfLevsInVec?begin:third;
4948       const double *p1=i+1<nbOfLevsInVec?end:begin;
4949       const double *p2=i+1<nbOfLevsInVec?third:end;
4950       double vecPlane[3]={
4951         (p1[1]-p0[1])*(p2[2]-p1[2])-(p1[2]-p0[2])*(p2[1]-p1[1]),
4952         (p1[2]-p0[2])*(p2[0]-p1[0])-(p1[0]-p0[0])*(p2[2]-p1[2]),
4953         (p1[0]-p0[0])*(p2[1]-p1[1])-(p1[1]-p0[1])*(p2[0]-p1[0]),
4954       };
4955       double norm=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]+vecPlane[2]*vecPlane[2]);
4956       if(norm>1.e-7)
4957         {
4958           vecPlane[0]/=norm; vecPlane[1]/=norm; vecPlane[2]/=norm;
4959           double norm2=sqrt(vecPlane[0]*vecPlane[0]+vecPlane[1]*vecPlane[1]);
4960           double vec2[2]={vecPlane[1]/norm2,-vecPlane[0]/norm2};
4961           double s2=norm2;
4962           double c2=cos(asin(s2));
4963           double m[3][3]={
4964             {vec2[0]*vec2[0]*(1-c2)+c2, vec2[0]*vec2[1]*(1-c2), vec2[1]*s2},
4965             {vec2[0]*vec2[1]*(1-c2), vec2[1]*vec2[1]*(1-c2)+c2, -vec2[0]*s2},
4966             {-vec2[1]*s2, vec2[0]*s2, c2}
4967           };
4968           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]};
4969           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]};
4970           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]};
4971           INTERP_KERNEL::EdgeArcCircle::GetArcOfCirclePassingThru(p0r,p1r,p2r,tmp3,radius,alpha,alpha0);
4972           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]);
4973           double angle=acos(cosangle/(radius*radius));
4974           tmp->rotate(end,vecPlane,angle);
4975         }
4976       retPtr=std::copy(tmp2->getConstPointer(),tmp2->getConstPointer()+tmp2->getNbOfElems(),retPtr);
4977     }
4978   return ret.retn();
4979 }
4980
4981 /*!
4982  * This method is private because not easy to use for end user. This method is const contrary to
4983  * MEDCouplingUMesh::buildExtrudedMesh method because this->_coords are expected to contain
4984  * the coords sorted slice by slice.
4985  * \param isQuad specifies presence of quadratic cells.
4986  */
4987 MEDCouplingUMesh *MEDCouplingUMesh::buildExtrudedMeshFromThisLowLev(int nbOfNodesOf1Lev, bool isQuad) const
4988 {
4989   int nbOf1DCells(getNumberOfNodes()/nbOfNodesOf1Lev-1);
4990   int nbOf2DCells(getNumberOfCells());
4991   int nbOf3DCells(nbOf2DCells*nbOf1DCells);
4992   MEDCouplingUMesh *ret(MEDCouplingUMesh::New("Extruded",getMeshDimension()+1));
4993   const int *conn(_nodal_connec->begin()),*connI(_nodal_connec_index->begin());
4994   MCAuto<DataArrayInt> newConn(DataArrayInt::New()),newConnI(DataArrayInt::New());
4995   newConnI->alloc(nbOf3DCells+1,1);
4996   int *newConnIPtr(newConnI->getPointer());
4997   *newConnIPtr++=0;
4998   std::vector<int> newc;
4999   for(int j=0;j<nbOf2DCells;j++)
5000     {
5001       AppendExtrudedCell(conn+connI[j],conn+connI[j+1],nbOfNodesOf1Lev,isQuad,newc);
5002       *newConnIPtr++=(int)newc.size();
5003     }
5004   newConn->alloc((int)(newc.size())*nbOf1DCells,1);
5005   int *newConnPtr(newConn->getPointer());
5006   int deltaPerLev(isQuad?2*nbOfNodesOf1Lev:nbOfNodesOf1Lev);
5007   newConnIPtr=newConnI->getPointer();
5008   for(int iz=0;iz<nbOf1DCells;iz++)
5009     {
5010       if(iz!=0)
5011         std::transform(newConnIPtr+1,newConnIPtr+1+nbOf2DCells,newConnIPtr+1+iz*nbOf2DCells,std::bind2nd(std::plus<int>(),newConnIPtr[iz*nbOf2DCells]));
5012       const int *posOfTypeOfCell(newConnIPtr);
5013       for(std::vector<int>::const_iterator iter=newc.begin();iter!=newc.end();iter++,newConnPtr++)
5014         {
5015           int icell((int)(iter-newc.begin()));//std::distance unfortunately cannot been called here in C++98
5016           if(icell!=*posOfTypeOfCell)
5017             {
5018               if(*iter!=-1)
5019                 *newConnPtr=(*iter)+iz*deltaPerLev;
5020               else
5021                 *newConnPtr=-1;
5022             }
5023           else
5024             {
5025               *newConnPtr=*iter;
5026               posOfTypeOfCell++;
5027             }
5028         }
5029     }
5030   ret->setConnectivity(newConn,newConnI,true);
5031   ret->setCoords(getCoords());
5032   return ret;
5033 }
5034
5035 /*!
5036  * Checks if \a this mesh is constituted by only quadratic cells.
5037  *  \return bool - \c true if there are only quadratic cells in \a this mesh.
5038  *  \throw If the coordinates array is not set.
5039  *  \throw If the nodal connectivity of cells is not defined.
5040  */
5041 bool MEDCouplingUMesh::isFullyQuadratic() const
5042 {
5043   checkFullyDefined();
5044   bool ret=true;
5045   int nbOfCells=getNumberOfCells();
5046   for(int i=0;i<nbOfCells && ret;i++)
5047     {
5048       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5049       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5050       ret=cm.isQuadratic();
5051     }
5052   return ret;
5053 }
5054
5055 /*!
5056  * Checks if \a this mesh includes any quadratic cell.
5057  *  \return bool - \c true if there is at least one quadratic cells in \a this mesh.
5058  *  \throw If the coordinates array is not set.
5059  *  \throw If the nodal connectivity of cells is not defined.
5060  */
5061 bool MEDCouplingUMesh::isPresenceOfQuadratic() const
5062 {
5063   checkFullyDefined();
5064   bool ret=false;
5065   int nbOfCells=getNumberOfCells();
5066   for(int i=0;i<nbOfCells && !ret;i++)
5067     {
5068       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5069       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5070       ret=cm.isQuadratic();
5071     }
5072   return ret;
5073 }
5074
5075 /*!
5076  * Converts all quadratic cells to linear ones. If there are no quadratic cells in \a
5077  * this mesh, it remains unchanged.
5078  *  \throw If the coordinates array is not set.
5079  *  \throw If the nodal connectivity of cells is not defined.
5080  */
5081 void MEDCouplingUMesh::convertQuadraticCellsToLinear()
5082 {
5083   checkFullyDefined();
5084   int nbOfCells=getNumberOfCells();
5085   int delta=0;
5086   const int *iciptr=_nodal_connec_index->getConstPointer();
5087   for(int i=0;i<nbOfCells;i++)
5088     {
5089       INTERP_KERNEL::NormalizedCellType type=getTypeOfCell(i);
5090       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5091       if(cm.isQuadratic())
5092         {
5093           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5094           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5095           if(!cml.isDynamic())
5096             delta+=cm.getNumberOfNodes()-cml.getNumberOfNodes();
5097           else
5098             delta+=(iciptr[i+1]-iciptr[i]-1)/2;
5099         }
5100     }
5101   if(delta==0)
5102     return ;
5103   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5104   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5105   const int *icptr=_nodal_connec->getConstPointer();
5106   newConn->alloc(getNodalConnectivityArrayLen()-delta,1);
5107   newConnI->alloc(nbOfCells+1,1);
5108   int *ocptr=newConn->getPointer();
5109   int *ociptr=newConnI->getPointer();
5110   *ociptr=0;
5111   _types.clear();
5112   for(int i=0;i<nbOfCells;i++,ociptr++)
5113     {
5114       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)icptr[iciptr[i]];
5115       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(type);
5116       if(!cm.isQuadratic())
5117         {
5118           _types.insert(type);
5119           ocptr=std::copy(icptr+iciptr[i],icptr+iciptr[i+1],ocptr);
5120           ociptr[1]=ociptr[0]+iciptr[i+1]-iciptr[i];
5121         }
5122       else
5123         {
5124           INTERP_KERNEL::NormalizedCellType typel=cm.getLinearType();
5125           _types.insert(typel);
5126           const INTERP_KERNEL::CellModel& cml=INTERP_KERNEL::CellModel::GetCellModel(typel);
5127           int newNbOfNodes=cml.getNumberOfNodes();
5128           if(cml.isDynamic())
5129             newNbOfNodes=(iciptr[i+1]-iciptr[i]-1)/2;
5130           *ocptr++=(int)typel;
5131           ocptr=std::copy(icptr+iciptr[i]+1,icptr+iciptr[i]+newNbOfNodes+1,ocptr);
5132           ociptr[1]=ociptr[0]+newNbOfNodes+1;
5133         }
5134     }
5135   setConnectivity(newConn,newConnI,false);
5136 }
5137
5138 /*!
5139  * This method converts all linear cell in \a this to quadratic one.
5140  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, here it is needed to specify the target
5141  * 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)
5142  * 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.
5143  * Contrary to MEDCouplingUMesh::convertQuadraticCellsToLinear method, the coordinates in \a this can be become bigger. All created nodes will be put at the
5144  * end of the existing coordinates.
5145  * 
5146  * \param [in] conversionType specifies the type of conversion expected. Only 0 (default) and 1 are supported presently. 0 those that creates the 'most' simple
5147  *             corresponding quadratic cells. 1 is those creating the 'most' complex.
5148  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5149  * 
5150  * \throw if \a this is not fully defined. It throws too if \a conversionType is not in [0,1].
5151  *
5152  * \sa MEDCouplingUMesh::convertQuadraticCellsToLinear
5153  */
5154 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic(int conversionType)
5155 {
5156   DataArrayInt *conn=0,*connI=0;
5157   DataArrayDouble *coords=0;
5158   std::set<INTERP_KERNEL::NormalizedCellType> types;
5159   checkFullyDefined();
5160   MCAuto<DataArrayInt> ret,connSafe,connISafe;
5161   MCAuto<DataArrayDouble> coordsSafe;
5162   int meshDim=getMeshDimension();
5163   switch(conversionType)
5164   {
5165     case 0:
5166       switch(meshDim)
5167       {
5168         case 1:
5169           ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);
5170           connSafe=conn; connISafe=connI; coordsSafe=coords;
5171           break;
5172         case 2:
5173           ret=convertLinearCellsToQuadratic2D0(conn,connI,coords,types);
5174           connSafe=conn; connISafe=connI; coordsSafe=coords;
5175           break;
5176         case 3:
5177           ret=convertLinearCellsToQuadratic3D0(conn,connI,coords,types);
5178           connSafe=conn; connISafe=connI; coordsSafe=coords;
5179           break;
5180         default:
5181           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 0 mesh dimensions available are [1,2,3] !");
5182       }
5183       break;
5184         case 1:
5185           {
5186             switch(meshDim)
5187             {
5188               case 1:
5189                 ret=convertLinearCellsToQuadratic1D0(conn,connI,coords,types);//it is not a bug. In 1D policy 0 and 1 are equals
5190                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5191                 break;
5192               case 2:
5193                 ret=convertLinearCellsToQuadratic2D1(conn,connI,coords,types);
5194                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5195                 break;
5196               case 3:
5197                 ret=convertLinearCellsToQuadratic3D1(conn,connI,coords,types);
5198                 connSafe=conn; connISafe=connI; coordsSafe=coords;
5199                 break;
5200               default:
5201                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion of type 1 mesh dimensions available are [1,2,3] !");
5202             }
5203             break;
5204           }
5205         default:
5206           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertLinearCellsToQuadratic : conversion type available are 0 (default, the simplest) and 1 (the most complex) !");
5207   }
5208   setConnectivity(connSafe,connISafe,false);
5209   _types=types;
5210   setCoords(coordsSafe);
5211   return ret.retn();
5212 }
5213
5214 /*!
5215  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5216  * so that the number of cells remains the same. Quadratic faces are converted to
5217  * polygons. This method works only for 2D meshes in
5218  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5219  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5220  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5221  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5222  *         a polylinized edge constituting the input polygon.
5223  *  \throw If the coordinates array is not set.
5224  *  \throw If the nodal connectivity of cells is not defined.
5225  *  \throw If \a this->getMeshDimension() != 2.
5226  *  \throw If \a this->getSpaceDimension() != 2.
5227  */
5228 void MEDCouplingUMesh::tessellate2D(double eps)
5229 {
5230   int meshDim(getMeshDimension()),spaceDim(getSpaceDimension());
5231   if(spaceDim!=2)
5232     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : works only with space dimension equal to 2 !");
5233   switch(meshDim)
5234     {
5235     case 1:
5236       return tessellate2DCurveInternal(eps);
5237     case 2:
5238       return tessellate2DInternal(eps);
5239     default:
5240       throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2D : mesh dimension must be in [1,2] !");
5241     }
5242 }
5243 /*!
5244  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5245  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5246  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5247  *         a sub-divided edge.
5248  *  \throw If the coordinates array is not set.
5249  *  \throw If the nodal connectivity of cells is not defined.
5250  *  \throw If \a this->getMeshDimension() != 1.
5251  *  \throw If \a this->getSpaceDimension() != 2.
5252  */
5253
5254 #if 0
5255 /*!
5256  * This method only works if \a this has spaceDimension equal to 2 and meshDimension also equal to 2.
5257  * This method allows to modify connectivity of cells in \a this that shares some edges in \a edgeIdsToBeSplit.
5258  * The nodes to be added in those 2D cells are defined by the pair of \a  nodeIdsToAdd and \a nodeIdsIndexToAdd.
5259  * Length of \a nodeIdsIndexToAdd is expected to equal to length of \a edgeIdsToBeSplit + 1.
5260  * The node ids in \a nodeIdsToAdd should be valid. Those nodes have to be sorted exactly following exactly the direction of the edge.
5261  * This method can be seen as the opposite method of colinearize2D.
5262  * 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
5263  * to avoid to modify the numbering of existing nodes.
5264  *
5265  * \param [in] nodeIdsToAdd - the list of node ids to be added (\a nodeIdsIndexToAdd array allows to walk on this array)
5266  * \param [in] nodeIdsIndexToAdd - the entry point of \a nodeIdsToAdd to point to the corresponding nodes to be added.
5267  * \param [in] mesh1Desc - 1st output of buildDescendingConnectivity2 on \a this.
5268  * \param [in] desc - 2nd output of buildDescendingConnectivity2 on \a this.
5269  * \param [in] descI - 3rd output of buildDescendingConnectivity2 on \a this.
5270  * \param [in] revDesc - 4th output of buildDescendingConnectivity2 on \a this.
5271  * \param [in] revDescI - 5th output of buildDescendingConnectivity2 on \a this.
5272  *
5273  * \sa buildDescendingConnectivity2
5274  */
5275 void MEDCouplingUMesh::splitSomeEdgesOf2DMesh(const DataArrayInt *nodeIdsToAdd, const DataArrayInt *nodeIdsIndexToAdd, const DataArrayInt *edgeIdsToBeSplit,
5276                                               const MEDCouplingUMesh *mesh1Desc, const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *revDesc, const DataArrayInt *revDescI)
5277 {
5278   if(!nodeIdsToAdd || !nodeIdsIndexToAdd || !edgeIdsToBeSplit || !mesh1Desc || !desc || !descI || !revDesc || !revDescI)
5279     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : input pointers must be not NULL !");
5280   nodeIdsToAdd->checkAllocated(); nodeIdsIndexToAdd->checkAllocated(); edgeIdsToBeSplit->checkAllocated(); desc->checkAllocated(); descI->checkAllocated(); revDesc->checkAllocated(); revDescI->checkAllocated();
5281   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
5282     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : this must have spacedim=meshdim=2 !");
5283   if(mesh1Desc->getSpaceDimension()!=2 || mesh1Desc->getMeshDimension()!=1)
5284     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitSomeEdgesOf2DMesh : mesh1Desc must be the explosion of this with spaceDim=2 and meshDim = 1 !");
5285   //DataArrayInt *out0(0),*outi0(0);
5286   //MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
5287   //MCAuto<DataArrayInt> out0s(out0),outi0s(outi0);
5288   //out0s=out0s->buildUnique(); out0s->sort(true);
5289 }
5290 #endif
5291
5292 /*!
5293  * Implementes \a conversionType 0 for meshes with meshDim = 1, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5294  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5295  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5296  */
5297 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic1D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5298 {
5299   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5300   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5301   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5302   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5303   int nbOfCells=getNumberOfCells();
5304   int nbOfNodes=getNumberOfNodes();
5305   const int *cPtr=_nodal_connec->getConstPointer();
5306   const int *icPtr=_nodal_connec_index->getConstPointer();
5307   int lastVal=0,offset=nbOfNodes;
5308   for(int i=0;i<nbOfCells;i++,icPtr++)
5309     {
5310       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5311       if(type==INTERP_KERNEL::NORM_SEG2)
5312         {
5313           types.insert(INTERP_KERNEL::NORM_SEG3);
5314           newConn->pushBackSilent((int)INTERP_KERNEL::NORM_SEG3);
5315           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[0]+3);
5316           newConn->pushBackSilent(offset++);
5317           lastVal+=4;
5318           newConnI->pushBackSilent(lastVal);
5319           ret->pushBackSilent(i);
5320         }
5321       else
5322         {
5323           types.insert(type);
5324           lastVal+=(icPtr[1]-icPtr[0]);
5325           newConnI->pushBackSilent(lastVal);
5326           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5327         }
5328     }
5329   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5330   coords=DataArrayDouble::Aggregate(getCoords(),tmp); conn=newConn.retn(); connI=newConnI.retn();
5331   return ret.retn();
5332 }
5333
5334 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
5335 {
5336   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5337   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5338   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5339   //
5340   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5341   DataArrayInt *conn1D=0,*conn1DI=0;
5342   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5343   DataArrayDouble *coordsTmp=0;
5344   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5345   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5346   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5347   const int *c1DPtr=conn1D->begin();
5348   const int *c1DIPtr=conn1DI->begin();
5349   int nbOfCells=getNumberOfCells();
5350   const int *cPtr=_nodal_connec->getConstPointer();
5351   const int *icPtr=_nodal_connec_index->getConstPointer();
5352   int lastVal=0;
5353   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5354     {
5355       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5356       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5357       if(!cm.isQuadratic())
5358         {
5359           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType();
5360           types.insert(typ2); newConn->pushBackSilent(typ2);
5361           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5362           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5363             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5364           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0]);
5365           newConnI->pushBackSilent(lastVal);
5366           ret->pushBackSilent(i);
5367         }
5368       else
5369         {
5370           types.insert(typ);
5371           lastVal+=(icPtr[1]-icPtr[0]);
5372           newConnI->pushBackSilent(lastVal);
5373           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5374         }
5375     }
5376   conn=newConn.retn(); connI=newConnI.retn(); coords=coordsTmpSafe.retn();
5377   return ret.retn();
5378 }
5379
5380 /*!
5381  * Implementes \a conversionType 0 for meshes with meshDim = 2, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5382  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5383  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5384  */
5385 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5386 {
5387   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5388   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5389   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5390 }
5391
5392 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic2D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5393 {
5394   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5395   MCAuto<MEDCouplingUMesh> m1D=buildDescendingConnectivity(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5396   //
5397   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5398   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5399   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
5400   //
5401   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5402   const int *descPtr(desc->begin()),*descIPtr(descI->begin());
5403   DataArrayInt *conn1D=0,*conn1DI=0;
5404   std::set<INTERP_KERNEL::NormalizedCellType> types1D;
5405   DataArrayDouble *coordsTmp=0;
5406   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=0;
5407   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5408   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5409   const int *c1DPtr=conn1D->begin();
5410   const int *c1DIPtr=conn1DI->begin();
5411   int nbOfCells=getNumberOfCells();
5412   const int *cPtr=_nodal_connec->getConstPointer();
5413   const int *icPtr=_nodal_connec_index->getConstPointer();
5414   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5415   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++)
5416     {
5417       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5418       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5419       if(!cm.isQuadratic())
5420         {
5421           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5422           types.insert(typ2); newConn->pushBackSilent(typ2);
5423           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5424           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5425             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5426           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5427           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+1;
5428           newConnI->pushBackSilent(lastVal);
5429           ret->pushBackSilent(i);
5430         }
5431       else
5432         {
5433           types.insert(typ);
5434           lastVal+=(icPtr[1]-icPtr[0]);
5435           newConnI->pushBackSilent(lastVal);
5436           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5437         }
5438     }
5439   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5440   coords=DataArrayDouble::Aggregate(coordsTmpSafe,tmp); conn=newConn.retn(); connI=newConnI.retn();
5441   return ret.retn();
5442 }
5443
5444 /*!
5445  * Implementes \a conversionType 0 for meshes with meshDim = 3, of MEDCouplingUMesh::convertLinearCellsToQuadratic method.
5446  * \return a newly created DataArrayInt instance that the caller should deal with containing cell ids of converted cells.
5447  * \sa MEDCouplingUMesh::convertLinearCellsToQuadratic.
5448  */
5449 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D0(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5450 {
5451   MCAuto<DataArrayInt> desc(DataArrayInt::New()),descI(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5452   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc,descI,tmp2,tmp3); tmp2=0; tmp3=0;
5453   return convertLinearCellsToQuadratic2DAnd3D0(m1D,desc,descI,conn,connI,coords,types);
5454 }
5455
5456 DataArrayInt *MEDCouplingUMesh::convertLinearCellsToQuadratic3D1(DataArrayInt *&conn, DataArrayInt *&connI, DataArrayDouble *& coords, std::set<INTERP_KERNEL::NormalizedCellType>& types) const
5457 {
5458   MCAuto<DataArrayInt> desc2(DataArrayInt::New()),desc2I(DataArrayInt::New()),tmp2(DataArrayInt::New()),tmp3(DataArrayInt::New());
5459   MCAuto<MEDCouplingUMesh> m2D=buildDescendingConnectivityGen<MinusOneSonsGeneratorBiQuadratic>(desc2,desc2I,tmp2,tmp3,MEDCouplingFastNbrer); tmp2=0; tmp3=0;
5460   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),desc1I(DataArrayInt::New()),tmp4(DataArrayInt::New()),tmp5(DataArrayInt::New());
5461   MCAuto<MEDCouplingUMesh> m1D=explode3DMeshTo1D(desc1,desc1I,tmp4,tmp5); tmp4=0; tmp5=0;
5462   //
5463   MCAuto<DataArrayInt> newConn=DataArrayInt::New(); newConn->alloc(0,1);
5464   MCAuto<DataArrayInt> newConnI=DataArrayInt::New(); newConnI->alloc(1,1); newConnI->setIJ(0,0,0);
5465   MCAuto<DataArrayInt> ret=DataArrayInt::New(),ret2=DataArrayInt::New(); ret->alloc(0,1); ret2->alloc(0,1);
5466   //
5467   MCAuto<DataArrayDouble> bary=computeCellCenterOfMass();
5468   const int *descPtr(desc1->begin()),*descIPtr(desc1I->begin()),*desc2Ptr(desc2->begin()),*desc2IPtr(desc2I->begin());
5469   DataArrayInt *conn1D=0,*conn1DI=0,*conn2D=0,*conn2DI=0;
5470   std::set<INTERP_KERNEL::NormalizedCellType> types1D,types2D;
5471   DataArrayDouble *coordsTmp=0,*coordsTmp2=0;
5472   MCAuto<DataArrayInt> ret1D=m1D->convertLinearCellsToQuadratic1D0(conn1D,conn1DI,coordsTmp,types1D); ret1D=DataArrayInt::New(); ret1D->alloc(0,1);
5473   MCAuto<DataArrayInt> conn1DSafe(conn1D),conn1DISafe(conn1DI);
5474   MCAuto<DataArrayDouble> coordsTmpSafe(coordsTmp);
5475   MCAuto<DataArrayInt> ret2D=m2D->convertLinearCellsToQuadratic2D1(conn2D,conn2DI,coordsTmp2,types2D); ret2D=DataArrayInt::New(); ret2D->alloc(0,1);
5476   MCAuto<DataArrayDouble> coordsTmp2Safe(coordsTmp2);
5477   MCAuto<DataArrayInt> conn2DSafe(conn2D),conn2DISafe(conn2DI);
5478   const int *c1DPtr=conn1D->begin(),*c1DIPtr=conn1DI->begin(),*c2DPtr=conn2D->begin(),*c2DIPtr=conn2DI->begin();
5479   int nbOfCells=getNumberOfCells();
5480   const int *cPtr=_nodal_connec->getConstPointer();
5481   const int *icPtr=_nodal_connec_index->getConstPointer();
5482   int lastVal=0,offset=coordsTmpSafe->getNumberOfTuples();
5483   for(int i=0;i<nbOfCells;i++,icPtr++,descIPtr++,desc2IPtr++)
5484     {
5485       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)cPtr[*icPtr];
5486       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
5487       if(!cm.isQuadratic())
5488         {
5489           INTERP_KERNEL::NormalizedCellType typ2=cm.getQuadraticType2();
5490           if(typ2==INTERP_KERNEL::NORM_ERROR)
5491             {
5492               std::ostringstream oss; oss << "MEDCouplingUMesh::convertLinearCellsToQuadratic3D1 : On cell #" << i << " the linear cell type does not support advanced quadratization !";
5493               throw INTERP_KERNEL::Exception(oss.str().c_str());
5494             }
5495           types.insert(typ2); newConn->pushBackSilent(typ2);
5496           newConn->pushBackValsSilent(cPtr+icPtr[0]+1,cPtr+icPtr[1]);
5497           for(const int *d=descPtr+descIPtr[0];d!=descPtr+descIPtr[1];d++)
5498             newConn->pushBackSilent(c1DPtr[c1DIPtr[*d]+3]);
5499           for(const int *d=desc2Ptr+desc2IPtr[0];d!=desc2Ptr+desc2IPtr[1];d++)
5500             {
5501               int nodeId2=c2DPtr[c2DIPtr[(*d)+1]-1];
5502               int tmpPos=newConn->getNumberOfTuples();
5503               newConn->pushBackSilent(nodeId2);
5504               ret2D->pushBackSilent(nodeId2); ret1D->pushBackSilent(tmpPos);
5505             }
5506           newConn->pushBackSilent(offset+ret->getNumberOfTuples());
5507           lastVal+=(icPtr[1]-icPtr[0])+(descIPtr[1]-descIPtr[0])+(desc2IPtr[1]-desc2IPtr[0])+1;
5508           newConnI->pushBackSilent(lastVal);
5509           ret->pushBackSilent(i);
5510         }
5511       else
5512         {
5513           types.insert(typ);
5514           lastVal+=(icPtr[1]-icPtr[0]);
5515           newConnI->pushBackSilent(lastVal);
5516           newConn->pushBackValsSilent(cPtr+icPtr[0],cPtr+icPtr[1]);
5517         }
5518     }
5519   MCAuto<DataArrayInt> diffRet2D=ret2D->getDifferentValues();
5520   MCAuto<DataArrayInt> o2nRet2D=diffRet2D->invertArrayN2O2O2N(coordsTmp2Safe->getNumberOfTuples());
5521   coordsTmp2Safe=coordsTmp2Safe->selectByTupleId(diffRet2D->begin(),diffRet2D->end());
5522   MCAuto<DataArrayDouble> tmp=bary->selectByTupleIdSafe(ret->begin(),ret->end());
5523   std::vector<const DataArrayDouble *> v(3); v[0]=coordsTmpSafe; v[1]=coordsTmp2Safe; v[2]=tmp;
5524   int *c=newConn->getPointer();
5525   const int *cI(newConnI->begin());
5526   for(const int *elt=ret1D->begin();elt!=ret1D->end();elt++)
5527     c[*elt]=o2nRet2D->getIJ(c[*elt],0)+offset;
5528   offset=coordsTmp2Safe->getNumberOfTuples();
5529   for(const int *elt=ret->begin();elt!=ret->end();elt++)
5530     c[cI[(*elt)+1]-1]+=offset;
5531   coords=DataArrayDouble::Aggregate(v); conn=newConn.retn(); connI=newConnI.retn();
5532   return ret.retn();
5533 }
5534
5535 /*!
5536  * Divides every cell of \a this mesh into simplices (triangles in 2D and tetrahedra in 3D).
5537  * In addition, returns an array mapping new cells to old ones. <br>
5538  * This method typically increases the number of cells in \a this mesh
5539  * but the number of nodes remains \b unchanged.
5540  * That's why the 3D splitting policies
5541  * INTERP_KERNEL::GENERAL_24 and INTERP_KERNEL::GENERAL_48 are not available here.
5542  *  \param [in] policy - specifies a pattern used for splitting.
5543  * The semantic of \a policy is:
5544  * - 0 - to split QUAD4 by cutting it along 0-2 diagonal (for 2D mesh only).
5545  * - 1 - to split QUAD4 by cutting it along 1-3 diagonal (for 2D mesh only).
5546  * - INTERP_KERNEL::PLANAR_FACE_5 - to split HEXA8  into 5 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5547  * - INTERP_KERNEL::PLANAR_FACE_6 - to split HEXA8  into 6 TETRA4 (for 3D mesh only - see INTERP_KERNEL::SplittingPolicy for an image).
5548  *
5549  *
5550  *  \return DataArrayInt * - a new instance of DataArrayInt holding, for each new cell,
5551  *          an id of old cell producing it. The caller is to delete this array using
5552  *         decrRef() as it is no more needed.
5553  *
5554  *  \throw If \a policy is 0 or 1 and \a this->getMeshDimension() != 2.
5555  *  \throw If \a policy is INTERP_KERNEL::PLANAR_FACE_5 or INTERP_KERNEL::PLANAR_FACE_6
5556  *          and \a this->getMeshDimension() != 3. 
5557  *  \throw If \a policy is not one of the four discussed above.
5558  *  \throw If the nodal connectivity of cells is not defined.
5559  * \sa MEDCouplingUMesh::tetrahedrize, MEDCoupling1SGTUMesh::sortHexa8EachOther
5560  */
5561 DataArrayInt *MEDCouplingUMesh::simplexize(int policy)
5562 {
5563   switch(policy)
5564   {
5565     case 0:
5566       return simplexizePol0();
5567     case 1:
5568       return simplexizePol1();
5569     case (int) INTERP_KERNEL::PLANAR_FACE_5:
5570         return simplexizePlanarFace5();
5571     case (int) INTERP_KERNEL::PLANAR_FACE_6:
5572         return simplexizePlanarFace6();
5573     default:
5574       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)");
5575   }
5576 }
5577
5578 /*!
5579  * Checks if \a this mesh is constituted by simplex cells only. Simplex cells are:
5580  * - 1D: INTERP_KERNEL::NORM_SEG2
5581  * - 2D: INTERP_KERNEL::NORM_TRI3
5582  * - 3D: INTERP_KERNEL::NORM_TETRA4.
5583  *
5584  * This method is useful for users that need to use P1 field services as
5585  * MEDCouplingFieldDouble::getValueOn(), MEDCouplingField::buildMeasureField() etc.
5586  * All these methods need mesh support containing only simplex cells.
5587  *  \return bool - \c true if there are only simplex cells in \a this mesh.
5588  *  \throw If the coordinates array is not set.
5589  *  \throw If the nodal connectivity of cells is not defined.
5590  *  \throw If \a this->getMeshDimension() < 1.
5591  */
5592 bool MEDCouplingUMesh::areOnlySimplexCells() const
5593 {
5594   checkFullyDefined();
5595   int mdim=getMeshDimension();
5596   if(mdim<1 || mdim>3)
5597     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::areOnlySimplexCells : only available with meshes having a meshdim 1, 2 or 3 !");
5598   int nbCells=getNumberOfCells();
5599   const int *conn=_nodal_connec->getConstPointer();
5600   const int *connI=_nodal_connec_index->getConstPointer();
5601   for(int i=0;i<nbCells;i++)
5602     {
5603       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5604       if(!cm.isSimplex())
5605         return false;
5606     }
5607   return true;
5608 }
5609
5610 /*!
5611  * This method implements policy 0 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5612  */
5613 DataArrayInt *MEDCouplingUMesh::simplexizePol0()
5614 {
5615   checkConnectivityFullyDefined();
5616   if(getMeshDimension()!=2)
5617     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5618   int nbOfCells=getNumberOfCells();
5619   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5620   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5621   ret->alloc(nbOfCells+nbOfCutCells,1);
5622   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5623   int *retPt=ret->getPointer();
5624   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5625   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5626   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5627   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5628   int *pt=newConn->getPointer();
5629   int *ptI=newConnI->getPointer();
5630   ptI[0]=0;
5631   const int *oldc=_nodal_connec->getConstPointer();
5632   const int *ci=_nodal_connec_index->getConstPointer();
5633   for(int i=0;i<nbOfCells;i++,ci++)
5634     {
5635       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5636         {
5637           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+3],
5638             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+3],oldc[ci[0]+4]};
5639           pt=std::copy(tmp,tmp+8,pt);
5640           ptI[1]=ptI[0]+4;
5641           ptI[2]=ptI[0]+8;
5642           *retPt++=i;
5643           *retPt++=i;
5644           ptI+=2;
5645         }
5646       else
5647         {
5648           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5649           ptI[1]=ptI[0]+ci[1]-ci[0];
5650           ptI++;
5651           *retPt++=i;
5652         }
5653     }
5654   _nodal_connec->decrRef();
5655   _nodal_connec=newConn.retn();
5656   _nodal_connec_index->decrRef();
5657   _nodal_connec_index=newConnI.retn();
5658   computeTypes();
5659   updateTime();
5660   return ret.retn();
5661 }
5662
5663 /*!
5664  * This method implements policy 1 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5665  */
5666 DataArrayInt *MEDCouplingUMesh::simplexizePol1()
5667 {
5668   checkConnectivityFullyDefined();
5669   if(getMeshDimension()!=2)
5670     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePol0 : this policy is only available for mesh with meshdim == 2 !");
5671   int nbOfCells=getNumberOfCells();
5672   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5673   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_QUAD4);
5674   ret->alloc(nbOfCells+nbOfCutCells,1);
5675   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5676   int *retPt=ret->getPointer();
5677   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5678   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5679   newConnI->alloc(nbOfCells+nbOfCutCells+1,1);
5680   newConn->alloc(getNodalConnectivityArrayLen()+3*nbOfCutCells,1);
5681   int *pt=newConn->getPointer();
5682   int *ptI=newConnI->getPointer();
5683   ptI[0]=0;
5684   const int *oldc=_nodal_connec->getConstPointer();
5685   const int *ci=_nodal_connec_index->getConstPointer();
5686   for(int i=0;i<nbOfCells;i++,ci++)
5687     {
5688       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_QUAD4)
5689         {
5690           const int tmp[8]={(int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+1],oldc[ci[0]+2],oldc[ci[0]+4],
5691             (int)INTERP_KERNEL::NORM_TRI3,oldc[ci[0]+2],oldc[ci[0]+3],oldc[ci[0]+4]};
5692           pt=std::copy(tmp,tmp+8,pt);
5693           ptI[1]=ptI[0]+4;
5694           ptI[2]=ptI[0]+8;
5695           *retPt++=i;
5696           *retPt++=i;
5697           ptI+=2;
5698         }
5699       else
5700         {
5701           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5702           ptI[1]=ptI[0]+ci[1]-ci[0];
5703           ptI++;
5704           *retPt++=i;
5705         }
5706     }
5707   _nodal_connec->decrRef();
5708   _nodal_connec=newConn.retn();
5709   _nodal_connec_index->decrRef();
5710   _nodal_connec_index=newConnI.retn();
5711   computeTypes();
5712   updateTime();
5713   return ret.retn();
5714 }
5715
5716 /*!
5717  * This method implements policy INTERP_KERNEL::PLANAR_FACE_5 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5718  */
5719 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace5()
5720 {
5721   checkConnectivityFullyDefined();
5722   if(getMeshDimension()!=3)
5723     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace5 : this policy is only available for mesh with meshdim == 3 !");
5724   int nbOfCells=getNumberOfCells();
5725   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5726   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5727   ret->alloc(nbOfCells+4*nbOfCutCells,1);
5728   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5729   int *retPt=ret->getPointer();
5730   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5731   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5732   newConnI->alloc(nbOfCells+4*nbOfCutCells+1,1);
5733   newConn->alloc(getNodalConnectivityArrayLen()+16*nbOfCutCells,1);//21
5734   int *pt=newConn->getPointer();
5735   int *ptI=newConnI->getPointer();
5736   ptI[0]=0;
5737   const int *oldc=_nodal_connec->getConstPointer();
5738   const int *ci=_nodal_connec_index->getConstPointer();
5739   for(int i=0;i<nbOfCells;i++,ci++)
5740     {
5741       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5742         {
5743           for(int j=0;j<5;j++,pt+=5,ptI++)
5744             {
5745               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5746               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];
5747               *retPt++=i;
5748               ptI[1]=ptI[0]+5;
5749             }
5750         }
5751       else
5752         {
5753           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5754           ptI[1]=ptI[0]+ci[1]-ci[0];
5755           ptI++;
5756           *retPt++=i;
5757         }
5758     }
5759   _nodal_connec->decrRef();
5760   _nodal_connec=newConn.retn();
5761   _nodal_connec_index->decrRef();
5762   _nodal_connec_index=newConnI.retn();
5763   computeTypes();
5764   updateTime();
5765   return ret.retn();
5766 }
5767
5768 /*!
5769  * This method implements policy INTERP_KERNEL::PLANAR_FACE_6 of virtual method MEDCoupling::MEDCouplingUMesh::simplexize.
5770  */
5771 DataArrayInt *MEDCouplingUMesh::simplexizePlanarFace6()
5772 {
5773   checkConnectivityFullyDefined();
5774   if(getMeshDimension()!=3)
5775     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::simplexizePlanarFace6 : this policy is only available for mesh with meshdim == 3 !");
5776   int nbOfCells=getNumberOfCells();
5777   MCAuto<DataArrayInt> ret=DataArrayInt::New();
5778   int nbOfCutCells=getNumberOfCellsWithType(INTERP_KERNEL::NORM_HEXA8);
5779   ret->alloc(nbOfCells+5*nbOfCutCells,1);
5780   if(nbOfCutCells==0) { ret->iota(0); return ret.retn(); }
5781   int *retPt=ret->getPointer();
5782   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5783   MCAuto<DataArrayInt> newConnI=DataArrayInt::New();
5784   newConnI->alloc(nbOfCells+5*nbOfCutCells+1,1);
5785   newConn->alloc(getNodalConnectivityArrayLen()+21*nbOfCutCells,1);
5786   int *pt=newConn->getPointer();
5787   int *ptI=newConnI->getPointer();
5788   ptI[0]=0;
5789   const int *oldc=_nodal_connec->getConstPointer();
5790   const int *ci=_nodal_connec_index->getConstPointer();
5791   for(int i=0;i<nbOfCells;i++,ci++)
5792     {
5793       if((INTERP_KERNEL::NormalizedCellType)oldc[ci[0]]==INTERP_KERNEL::NORM_HEXA8)
5794         {
5795           for(int j=0;j<6;j++,pt+=5,ptI++)
5796             {
5797               pt[0]=(int)INTERP_KERNEL::NORM_TETRA4;
5798               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];
5799               *retPt++=i;
5800               ptI[1]=ptI[0]+5;
5801             }
5802         }
5803       else
5804         {
5805           pt=std::copy(oldc+ci[0],oldc+ci[1],pt);
5806           ptI[1]=ptI[0]+ci[1]-ci[0];
5807           ptI++;
5808           *retPt++=i;
5809         }
5810     }
5811   _nodal_connec->decrRef();
5812   _nodal_connec=newConn.retn();
5813   _nodal_connec_index->decrRef();
5814   _nodal_connec_index=newConnI.retn();
5815   computeTypes();
5816   updateTime();
5817   return ret.retn();
5818 }
5819
5820 /*!
5821  * Tessellates \a this 2D mesh by dividing not straight edges of quadratic faces,
5822  * so that the number of cells remains the same. Quadratic faces are converted to
5823  * polygons. This method works only for 2D meshes in
5824  * 2D space. If no cells are quadratic (INTERP_KERNEL::NORM_QUAD8,
5825  * INTERP_KERNEL::NORM_TRI6, INTERP_KERNEL::NORM_QPOLYG ), \a this mesh remains unchanged.
5826  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5827  *  \param [in] eps - specifies the maximal angle (in radians) between 2 sub-edges of
5828  *         a polylinized edge constituting the input polygon.
5829  *  \throw If the coordinates array is not set.
5830  *  \throw If the nodal connectivity of cells is not defined.
5831  *  \throw If \a this->getMeshDimension() != 2.
5832  *  \throw If \a this->getSpaceDimension() != 2.
5833  */
5834 void MEDCouplingUMesh::tessellate2DInternal(double eps)
5835 {
5836   checkFullyDefined();
5837   if(getMeshDimension()!=2 || getSpaceDimension()!=2)  
5838     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DInternal works on umeshes with meshdim equal to 2 and spaceDim equal to 2 too!");
5839   double epsa=fabs(eps);
5840   if(epsa<std::numeric_limits<double>::min())
5841     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 !");
5842   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
5843   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
5844   revDesc1=0; revDescIndx1=0;
5845   mDesc->tessellate2D(eps);
5846   subDivide2DMesh(mDesc->_nodal_connec->getConstPointer(),mDesc->_nodal_connec_index->getConstPointer(),desc1->getConstPointer(),descIndx1->getConstPointer());
5847   setCoords(mDesc->getCoords());
5848 }
5849
5850 /*!
5851  * Tessellates \a this 1D mesh in 2D space by dividing not straight quadratic edges.
5852  * \warning This method can lead to a huge amount of nodes if \a eps is very low.
5853  *  \param [in] eps - specifies the maximal angle (in radian) between 2 sub-edges of
5854  *         a sub-divided edge.
5855  *  \throw If the coordinates array is not set.
5856  *  \throw If the nodal connectivity of cells is not defined.
5857  *  \throw If \a this->getMeshDimension() != 1.
5858  *  \throw If \a this->getSpaceDimension() != 2.
5859  */
5860 void MEDCouplingUMesh::tessellate2DCurveInternal(double eps)
5861 {
5862   checkFullyDefined();
5863   if(getMeshDimension()!=1 || getSpaceDimension()!=2)
5864     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tessellate2DCurveInternal works on umeshes with meshdim equal to 1 and spaceDim equal to 2 too!");
5865   double epsa=fabs(eps);
5866   if(epsa<std::numeric_limits<double>::min())
5867     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 !");
5868   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=1.e-10;
5869   int nbCells=getNumberOfCells();
5870   int nbNodes=getNumberOfNodes();
5871   const int *conn=_nodal_connec->getConstPointer();
5872   const int *connI=_nodal_connec_index->getConstPointer();
5873   const double *coords=_coords->getConstPointer();
5874   std::vector<double> addCoo;
5875   std::vector<int> newConn;//no direct DataArrayInt because interface with Geometric2D
5876   MCAuto<DataArrayInt> newConnI(DataArrayInt::New());
5877   newConnI->alloc(nbCells+1,1);
5878   int *newConnIPtr=newConnI->getPointer();
5879   *newConnIPtr=0;
5880   int tmp1[3];
5881   INTERP_KERNEL::Node *tmp2[3];
5882   std::set<INTERP_KERNEL::NormalizedCellType> types;
5883   for(int i=0;i<nbCells;i++,newConnIPtr++)
5884     {
5885       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5886       if(cm.isQuadratic())
5887         {//assert(connI[i+1]-connI[i]-1==3)
5888           tmp1[0]=conn[connI[i]+1+0]; tmp1[1]=conn[connI[i]+1+1]; tmp1[2]=conn[connI[i]+1+2];
5889           tmp2[0]=new INTERP_KERNEL::Node(coords[2*tmp1[0]],coords[2*tmp1[0]+1]);
5890           tmp2[1]=new INTERP_KERNEL::Node(coords[2*tmp1[1]],coords[2*tmp1[1]+1]);
5891           tmp2[2]=new INTERP_KERNEL::Node(coords[2*tmp1[2]],coords[2*tmp1[2]+1]);
5892           INTERP_KERNEL::EdgeArcCircle *eac=INTERP_KERNEL::EdgeArcCircle::BuildFromNodes(tmp2[0],tmp2[2],tmp2[1]);
5893           if(eac)
5894             {
5895               eac->tesselate(tmp1,nbNodes,epsa,newConn,addCoo);
5896               types.insert((INTERP_KERNEL::NormalizedCellType)newConn[newConnIPtr[0]]);
5897               delete eac;
5898               newConnIPtr[1]=(int)newConn.size();
5899             }
5900           else
5901             {
5902               types.insert(INTERP_KERNEL::NORM_SEG2);
5903               newConn.push_back(INTERP_KERNEL::NORM_SEG2);
5904               newConn.insert(newConn.end(),conn+connI[i]+1,conn+connI[i]+3);
5905               newConnIPtr[1]=newConnIPtr[0]+3;
5906             }
5907         }
5908       else
5909         {
5910           types.insert((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
5911           newConn.insert(newConn.end(),conn+connI[i],conn+connI[i+1]);
5912           newConnIPtr[1]=newConnIPtr[0]+3;
5913         }
5914     }
5915   if(addCoo.empty() && ((int)newConn.size())==_nodal_connec->getNumberOfTuples())//nothing happens during tessellation : no update needed
5916     return ;
5917   _types=types;
5918   DataArrayInt::SetArrayIn(newConnI,_nodal_connec_index);
5919   MCAuto<DataArrayInt> newConnArr=DataArrayInt::New();
5920   newConnArr->alloc((int)newConn.size(),1);
5921   std::copy(newConn.begin(),newConn.end(),newConnArr->getPointer());
5922   DataArrayInt::SetArrayIn(newConnArr,_nodal_connec);
5923   MCAuto<DataArrayDouble> newCoords=DataArrayDouble::New();
5924   newCoords->alloc(nbNodes+((int)addCoo.size())/2,2);
5925   double *work=std::copy(_coords->begin(),_coords->end(),newCoords->getPointer());
5926   std::copy(addCoo.begin(),addCoo.end(),work);
5927   DataArrayDouble::SetArrayIn(newCoords,_coords);
5928   updateTime();
5929 }
5930
5931 /*!
5932  * 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.
5933  * This method completly ignore coordinates.
5934  * \param nodeSubdived is the nodal connectivity of subdivision of edges
5935  * \param nodeIndxSubdived is the nodal connectivity index of subdivision of edges
5936  * \param desc is descending connectivity in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5937  * \param descIndex is descending connectivity index in format specified in MEDCouplingUMesh::buildDescendingConnectivity2
5938  */
5939 void MEDCouplingUMesh::subDivide2DMesh(const int *nodeSubdived, const int *nodeIndxSubdived, const int *desc, const int *descIndex)
5940 {
5941   checkFullyDefined();
5942   if(getMeshDimension()!=2)
5943     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : works only on umesh with meshdim==2 !");
5944   int nbOfCells=getNumberOfCells();
5945   int *connI=_nodal_connec_index->getPointer();
5946   int newConnLgth=0;
5947   for(int i=0;i<nbOfCells;i++,connI++)
5948     {
5949       int offset=descIndex[i];
5950       int nbOfEdges=descIndex[i+1]-offset;
5951       //
5952       bool ddirect=desc[offset+nbOfEdges-1]>0;
5953       int eedgeId=std::abs(desc[offset+nbOfEdges-1])-1;
5954       int ref=ddirect?nodeSubdived[nodeIndxSubdived[eedgeId+1]-1]:nodeSubdived[nodeIndxSubdived[eedgeId]+1];
5955       for(int j=0;j<nbOfEdges;j++)
5956         {
5957           bool direct=desc[offset+j]>0;
5958           int edgeId=std::abs(desc[offset+j])-1;
5959           if(!INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodeSubdived[nodeIndxSubdived[edgeId]]).isQuadratic())
5960             {
5961               int id1=nodeSubdived[nodeIndxSubdived[edgeId]+1];
5962               int id2=nodeSubdived[nodeIndxSubdived[edgeId+1]-1];
5963               int ref2=direct?id1:id2;
5964               if(ref==ref2)
5965                 {
5966                   int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
5967                   newConnLgth+=nbOfSubNodes-1;
5968                   ref=direct?id2:id1;
5969                 }
5970               else
5971                 {
5972                   std::ostringstream oss; oss << "MEDCouplingUMesh::subDivide2DMesh : On polygon #" << i << " edgeid #" << j << " subedges mismatch : end subedge k!=start subedge k+1 !";
5973                   throw INTERP_KERNEL::Exception(oss.str().c_str());
5974                 }
5975             }
5976           else
5977             {
5978               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::subDivide2DMesh : this method only subdivides into linear edges !");
5979             }
5980         }
5981       newConnLgth++;//+1 is for cell type
5982       connI[1]=newConnLgth;
5983     }
5984   //
5985   MCAuto<DataArrayInt> newConn=DataArrayInt::New();
5986   newConn->alloc(newConnLgth,1);
5987   int *work=newConn->getPointer();
5988   for(int i=0;i<nbOfCells;i++)
5989     {
5990       *work++=INTERP_KERNEL::NORM_POLYGON;
5991       int offset=descIndex[i];
5992       int nbOfEdges=descIndex[i+1]-offset;
5993       for(int j=0;j<nbOfEdges;j++)
5994         {
5995           bool direct=desc[offset+j]>0;
5996           int edgeId=std::abs(desc[offset+j])-1;
5997           if(direct)
5998             work=std::copy(nodeSubdived+nodeIndxSubdived[edgeId]+1,nodeSubdived+nodeIndxSubdived[edgeId+1]-1,work);
5999           else
6000             {
6001               int nbOfSubNodes=nodeIndxSubdived[edgeId+1]-nodeIndxSubdived[edgeId]-1;
6002               std::reverse_iterator<const int *> it(nodeSubdived+nodeIndxSubdived[edgeId+1]);
6003               work=std::copy(it,it+nbOfSubNodes-1,work);
6004             }
6005         }
6006     }
6007   DataArrayInt::SetArrayIn(newConn,_nodal_connec);
6008   _types.clear();
6009   if(nbOfCells>0)
6010     _types.insert(INTERP_KERNEL::NORM_POLYGON);
6011 }
6012
6013 /*!
6014  * Converts degenerated 2D or 3D linear cells of \a this mesh into cells of simpler
6015  * type. For example an INTERP_KERNEL::NORM_QUAD4 cell having only three unique nodes in
6016  * its connectivity is transformed into an INTERP_KERNEL::NORM_TRI3 cell. This method
6017  * does \b not perform geometrical checks and checks only nodal connectivity of cells,
6018  * so it can be useful to call mergeNodes() before calling this method.
6019  *  \throw If \a this->getMeshDimension() <= 1.
6020  *  \throw If the coordinates array is not set.
6021  *  \throw If the nodal connectivity of cells is not defined.
6022  */
6023 void MEDCouplingUMesh::convertDegeneratedCells()
6024 {
6025   checkFullyDefined();
6026   if(getMeshDimension()<=1)
6027     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertDegeneratedCells works on umeshes with meshdim equals to 2 or 3 !");
6028   int nbOfCells=getNumberOfCells();
6029   if(nbOfCells<1)
6030     return ;
6031   int initMeshLgth=getNodalConnectivityArrayLen();
6032   int *conn=_nodal_connec->getPointer();
6033   int *index=_nodal_connec_index->getPointer();
6034   int posOfCurCell=0;
6035   int newPos=0;
6036   int lgthOfCurCell;
6037   for(int i=0;i<nbOfCells;i++)
6038     {
6039       lgthOfCurCell=index[i+1]-posOfCurCell;
6040       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[posOfCurCell];
6041       int newLgth;
6042       INTERP_KERNEL::NormalizedCellType newType=INTERP_KERNEL::CellSimplify::simplifyDegeneratedCell(type,conn+posOfCurCell+1,lgthOfCurCell-1,
6043                                                                                                      conn+newPos+1,newLgth);
6044       conn[newPos]=newType;
6045       newPos+=newLgth+1;
6046       posOfCurCell=index[i+1];
6047       index[i+1]=newPos;
6048     }
6049   if(newPos!=initMeshLgth)
6050     _nodal_connec->reAlloc(newPos);
6051   computeTypes();
6052 }
6053
6054 /*!
6055  * Finds incorrectly oriented cells of this 2D mesh in 3D space.
6056  * A cell is considered to be oriented correctly if an angle between its
6057  * normal vector and a given vector is less than \c PI / \c 2.
6058  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6059  *         cells. 
6060  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6061  *         checked.
6062  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6063  *         is not cleared before filling in.
6064  *  \throw If \a this->getMeshDimension() != 2.
6065  *  \throw If \a this->getSpaceDimension() != 3.
6066  *
6067  *  \if ENABLE_EXAMPLES
6068  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6069  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6070  *  \endif
6071  */
6072 void MEDCouplingUMesh::are2DCellsNotCorrectlyOriented(const double *vec, bool polyOnly, std::vector<int>& cells) const
6073 {
6074   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6075     throw INTERP_KERNEL::Exception("Invalid mesh to apply are2DCellsNotCorrectlyOriented on it : must be meshDim==2 and spaceDim==3 !");
6076   int nbOfCells=getNumberOfCells();
6077   const int *conn=_nodal_connec->getConstPointer();
6078   const int *connI=_nodal_connec_index->getConstPointer();
6079   const double *coordsPtr=_coords->getConstPointer();
6080   for(int i=0;i<nbOfCells;i++)
6081     {
6082       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6083       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6084         {
6085           bool isQuadratic=INTERP_KERNEL::CellModel::GetCellModel(type).isQuadratic();
6086           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6087             cells.push_back(i);
6088         }
6089     }
6090 }
6091
6092 /*!
6093  * Reverse connectivity of 2D cells whose orientation is not correct. A cell is
6094  * considered to be oriented correctly if an angle between its normal vector and a
6095  * given vector is less than \c PI / \c 2. 
6096  *  \param [in] vec - 3 components of the vector specifying the correct orientation of
6097  *         cells. 
6098  *  \param [in] polyOnly - if \c true, only polygons are checked, else, all cells are
6099  *         checked.
6100  *  \throw If \a this->getMeshDimension() != 2.
6101  *  \throw If \a this->getSpaceDimension() != 3.
6102  *
6103  *  \if ENABLE_EXAMPLES
6104  *  \ref cpp_mcumesh_are2DCellsNotCorrectlyOriented "Here is a C++ example".<br>
6105  *  \ref  py_mcumesh_are2DCellsNotCorrectlyOriented "Here is a Python example".
6106  *  \endif
6107  *
6108  *  \sa changeOrientationOfCells
6109  */
6110 void MEDCouplingUMesh::orientCorrectly2DCells(const double *vec, bool polyOnly)
6111 {
6112   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6113     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectly2DCells on it : must be meshDim==2 and spaceDim==3 !");
6114   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6115   const int *connI(_nodal_connec_index->getConstPointer());
6116   const double *coordsPtr(_coords->getConstPointer());
6117   bool isModified(false);
6118   for(int i=0;i<nbOfCells;i++)
6119     {
6120       INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6121       if(!polyOnly || (type==INTERP_KERNEL::NORM_POLYGON || type==INTERP_KERNEL::NORM_QPOLYG))
6122         {
6123           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6124           bool isQuadratic(cm.isQuadratic());
6125           if(!IsPolygonWellOriented(isQuadratic,vec,conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6126             {
6127               isModified=true;
6128               cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6129             }
6130         }
6131     }
6132   if(isModified)
6133     _nodal_connec->declareAsNew();
6134   updateTime();
6135 }
6136
6137 /*!
6138  * This method change the orientation of cells in \a this without any consideration of coordinates. Only connectivity is impacted.
6139  *
6140  * \sa orientCorrectly2DCells
6141  */
6142 void MEDCouplingUMesh::changeOrientationOfCells()
6143 {
6144   int mdim(getMeshDimension());
6145   if(mdim!=2 && mdim!=1)
6146     throw INTERP_KERNEL::Exception("Invalid mesh to apply changeOrientationOfCells on it : must be meshDim==2 or meshDim==1 !");
6147   int nbOfCells(getNumberOfCells()),*conn(_nodal_connec->getPointer());
6148   const int *connI(_nodal_connec_index->getConstPointer());
6149   if(mdim==2)
6150     {//2D
6151       for(int i=0;i<nbOfCells;i++)
6152         {
6153           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6154           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6155           cm.changeOrientationOf2D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6156         }
6157     }
6158   else
6159     {//1D
6160       for(int i=0;i<nbOfCells;i++)
6161         {
6162           INTERP_KERNEL::NormalizedCellType type((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6163           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(type));
6164           cm.changeOrientationOf1D(conn+connI[i]+1,(unsigned int)(connI[i+1]-connI[i]-1));
6165         }
6166     }
6167 }
6168
6169 /*!
6170  * Finds incorrectly oriented polyhedral cells, i.e. polyhedrons having correctly
6171  * oriented facets. The normal vector of the facet should point out of the cell.
6172  *  \param [in,out] cells - a vector returning ids of incorrectly oriented cells. It
6173  *         is not cleared before filling in.
6174  *  \throw If \a this->getMeshDimension() != 3.
6175  *  \throw If \a this->getSpaceDimension() != 3.
6176  *  \throw If the coordinates array is not set.
6177  *  \throw If the nodal connectivity of cells is not defined.
6178  *
6179  *  \if ENABLE_EXAMPLES
6180  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6181  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6182  *  \endif
6183  */
6184 void MEDCouplingUMesh::arePolyhedronsNotCorrectlyOriented(std::vector<int>& cells) const
6185 {
6186   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6187     throw INTERP_KERNEL::Exception("Invalid mesh to apply arePolyhedronsNotCorrectlyOriented on it : must be meshDim==3 and spaceDim==3 !");
6188   int nbOfCells=getNumberOfCells();
6189   const int *conn=_nodal_connec->getConstPointer();
6190   const int *connI=_nodal_connec_index->getConstPointer();
6191   const double *coordsPtr=_coords->getConstPointer();
6192   for(int i=0;i<nbOfCells;i++)
6193     {
6194       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6195       if(type==INTERP_KERNEL::NORM_POLYHED)
6196         {
6197           if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6198             cells.push_back(i);
6199         }
6200     }
6201 }
6202
6203 /*!
6204  * Tries to fix connectivity of polyhedra, so that normal vector of all facets to point
6205  * out of the cell. 
6206  *  \throw If \a this->getMeshDimension() != 3.
6207  *  \throw If \a this->getSpaceDimension() != 3.
6208  *  \throw If the coordinates array is not set.
6209  *  \throw If the nodal connectivity of cells is not defined.
6210  *  \throw If the reparation fails.
6211  *
6212  *  \if ENABLE_EXAMPLES
6213  *  \ref cpp_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a C++ example".<br>
6214  *  \ref  py_mcumesh_arePolyhedronsNotCorrectlyOriented "Here is a Python example".
6215  *  \endif
6216  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6217  */
6218 void MEDCouplingUMesh::orientCorrectlyPolyhedrons()
6219 {
6220   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6221     throw INTERP_KERNEL::Exception("Invalid mesh to apply orientCorrectlyPolyhedrons on it : must be meshDim==3 and spaceDim==3 !");
6222   int nbOfCells=getNumberOfCells();
6223   int *conn=_nodal_connec->getPointer();
6224   const int *connI=_nodal_connec_index->getConstPointer();
6225   const double *coordsPtr=_coords->getConstPointer();
6226   for(int i=0;i<nbOfCells;i++)
6227     {
6228       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6229       if(type==INTERP_KERNEL::NORM_POLYHED)
6230         {
6231           try
6232           {
6233               if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6234                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6235           }
6236           catch(INTERP_KERNEL::Exception& e)
6237           {
6238               std::ostringstream oss; oss << "Something wrong in polyhedron #" << i << " : " << e.what();
6239               throw INTERP_KERNEL::Exception(oss.str().c_str());
6240           }
6241         }
6242     }
6243   updateTime();
6244 }
6245
6246 /*!
6247  * Finds and fixes incorrectly oriented linear extruded volumes (INTERP_KERNEL::NORM_HEXA8,
6248  * INTERP_KERNEL::NORM_PENTA6, INTERP_KERNEL::NORM_HEXGP12 etc) to respect the MED convention
6249  * according to which the first facet of the cell should be oriented to have the normal vector
6250  * pointing out of cell.
6251  *  \return DataArrayInt * - a new instance of DataArrayInt holding ids of fixed
6252  *         cells. The caller is to delete this array using decrRef() as it is no more
6253  *         needed. 
6254  *  \throw If \a this->getMeshDimension() != 3.
6255  *  \throw If \a this->getSpaceDimension() != 3.
6256  *  \throw If the coordinates array is not set.
6257  *  \throw If the nodal connectivity of cells is not defined.
6258  *
6259  *  \if ENABLE_EXAMPLES
6260  *  \ref cpp_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a C++ example".<br>
6261  *  \ref  py_mcumesh_findAndCorrectBadOriented3DExtrudedCells "Here is a Python example".
6262  *  \endif
6263  * \sa MEDCouplingUMesh::findAndCorrectBadOriented3DCells
6264  */
6265 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DExtrudedCells()
6266 {
6267   const char msg[]="check3DCellsWellOriented detection works only for 3D cells !";
6268   if(getMeshDimension()!=3)
6269     throw INTERP_KERNEL::Exception(msg);
6270   int spaceDim=getSpaceDimension();
6271   if(spaceDim!=3)
6272     throw INTERP_KERNEL::Exception(msg);
6273   //
6274   int nbOfCells=getNumberOfCells();
6275   int *conn=_nodal_connec->getPointer();
6276   const int *connI=_nodal_connec_index->getConstPointer();
6277   const double *coo=getCoords()->getConstPointer();
6278   MCAuto<DataArrayInt> cells(DataArrayInt::New()); cells->alloc(0,1);
6279   for(int i=0;i<nbOfCells;i++)
6280     {
6281       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[connI[i]]);
6282       if(cm.isExtruded() && !cm.isDynamic() && !cm.isQuadratic())
6283         {
6284           if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coo))
6285             {
6286               CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6287               cells->pushBackSilent(i);
6288             }
6289         }
6290     }
6291   return cells.retn();
6292 }
6293
6294 /*!
6295  * This method is a faster method to correct orientation of all 3D cells in \a this.
6296  * 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.
6297  * This method makes the hypothesis that \a this a coherent that is to say MEDCouplingUMesh::checkConsistency should throw no exception.
6298  * 
6299  * \return a newly allocated int array with one components containing cell ids renumbered to fit the convention of MED (MED file and MEDCoupling)
6300  * \sa MEDCouplingUMesh::orientCorrectlyPolyhedrons, 
6301  */
6302 DataArrayInt *MEDCouplingUMesh::findAndCorrectBadOriented3DCells()
6303 {
6304   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
6305     throw INTERP_KERNEL::Exception("Invalid mesh to apply findAndCorrectBadOriented3DCells on it : must be meshDim==3 and spaceDim==3 !");
6306   int nbOfCells=getNumberOfCells();
6307   int *conn=_nodal_connec->getPointer();
6308   const int *connI=_nodal_connec_index->getConstPointer();
6309   const double *coordsPtr=_coords->getConstPointer();
6310   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(0,1);
6311   for(int i=0;i<nbOfCells;i++)
6312     {
6313       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)conn[connI[i]];
6314       switch(type)
6315       {
6316         case INTERP_KERNEL::NORM_TETRA4:
6317           {
6318             if(!IsTetra4WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6319               {
6320                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+3));
6321                 ret->pushBackSilent(i);
6322               }
6323             break;
6324           }
6325         case INTERP_KERNEL::NORM_PYRA5:
6326           {
6327             if(!IsPyra5WellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6328               {
6329                 std::swap(*(conn+connI[i]+2),*(conn+connI[i]+4));
6330                 ret->pushBackSilent(i);
6331               }
6332             break;
6333           }
6334         case INTERP_KERNEL::NORM_PENTA6:
6335         case INTERP_KERNEL::NORM_HEXA8:
6336         case INTERP_KERNEL::NORM_HEXGP12:
6337           {
6338             if(!Is3DExtrudedStaticCellWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6339               {
6340                 CorrectExtrudedStaticCell(conn+connI[i]+1,conn+connI[i+1]);
6341                 ret->pushBackSilent(i);
6342               }
6343             break;
6344           }
6345         case INTERP_KERNEL::NORM_POLYHED:
6346           {
6347             if(!IsPolyhedronWellOriented(conn+connI[i]+1,conn+connI[i+1],coordsPtr))
6348               {
6349                 TryToCorrectPolyhedronOrientation(conn+connI[i]+1,conn+connI[i+1],coordsPtr);
6350                 ret->pushBackSilent(i);
6351               }
6352             break;
6353           }
6354         default:
6355           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 !");
6356       }
6357     }
6358   updateTime();
6359   return ret.retn();
6360 }
6361
6362 /*!
6363  * This method has a sense for meshes with spaceDim==3 and meshDim==2.
6364  * If it is not the case an exception will be thrown.
6365  * This method is fast because the first cell of \a this is used to compute the plane.
6366  * \param vec output of size at least 3 used to store the normal vector (with norm equal to Area ) of searched plane.
6367  * \param pos output of size at least 3 used to store a point owned of searched plane.
6368  */
6369 void MEDCouplingUMesh::getFastAveragePlaneOfThis(double *vec, double *pos) const
6370 {
6371   if(getMeshDimension()!=2 || getSpaceDimension()!=3)
6372     throw INTERP_KERNEL::Exception("Invalid mesh to apply getFastAveragePlaneOfThis on it : must be meshDim==2 and spaceDim==3 !");
6373   const int *conn=_nodal_connec->getConstPointer();
6374   const int *connI=_nodal_connec_index->getConstPointer();
6375   const double *coordsPtr=_coords->getConstPointer();
6376   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(conn+1,connI[1]-connI[0]-1,coordsPtr,vec);
6377   std::copy(coordsPtr+3*conn[1],coordsPtr+3*conn[1]+3,pos);
6378 }
6379
6380 /*!
6381  * Creates a new MEDCouplingFieldDouble holding Edge Ratio values of all
6382  * cells. Currently cells of the following types are treated:
6383  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6384  * For a cell of other type an exception is thrown.
6385  * Space dimension of a 2D mesh can be either 2 or 3.
6386  * The Edge Ratio of a cell \f$t\f$ is: 
6387  *  \f$\frac{|t|_\infty}{|t|_0}\f$,
6388  *  where \f$|t|_\infty\f$ and \f$|t|_0\f$ respectively denote the greatest and
6389  *  the smallest edge lengths of \f$t\f$.
6390  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6391  *          cells and one time, lying on \a this mesh. The caller is to delete this
6392  *          field using decrRef() as it is no more needed. 
6393  *  \throw If the coordinates array is not set.
6394  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6395  *  \throw If the connectivity data array has more than one component.
6396  *  \throw If the connectivity data array has a named component.
6397  *  \throw If the connectivity index data array has more than one component.
6398  *  \throw If the connectivity index data array has a named component.
6399  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6400  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6401  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6402  */
6403 MEDCouplingFieldDouble *MEDCouplingUMesh::getEdgeRatioField() const
6404 {
6405   checkConsistencyLight();
6406   int spaceDim=getSpaceDimension();
6407   int meshDim=getMeshDimension();
6408   if(spaceDim!=2 && spaceDim!=3)
6409     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : SpaceDimension must be equal to 2 or 3 !");
6410   if(meshDim!=2 && meshDim!=3)
6411     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : MeshDimension must be equal to 2 or 3 !");
6412   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6413   ret->setMesh(this);
6414   int nbOfCells=getNumberOfCells();
6415   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6416   arr->alloc(nbOfCells,1);
6417   double *pt=arr->getPointer();
6418   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6419   const int *conn=_nodal_connec->getConstPointer();
6420   const int *connI=_nodal_connec_index->getConstPointer();
6421   const double *coo=_coords->getConstPointer();
6422   double tmp[12];
6423   for(int i=0;i<nbOfCells;i++,pt++)
6424     {
6425       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6426       switch(t)
6427       {
6428         case INTERP_KERNEL::NORM_TRI3:
6429           {
6430             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6431             *pt=INTERP_KERNEL::triEdgeRatio(tmp);
6432             break;
6433           }
6434         case INTERP_KERNEL::NORM_QUAD4:
6435           {
6436             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6437             *pt=INTERP_KERNEL::quadEdgeRatio(tmp);
6438             break;
6439           }
6440         case INTERP_KERNEL::NORM_TETRA4:
6441           {
6442             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6443             *pt=INTERP_KERNEL::tetraEdgeRatio(tmp);
6444             break;
6445           }
6446         default:
6447           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getEdgeRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6448       }
6449       conn+=connI[i+1]-connI[i];
6450     }
6451   ret->setName("EdgeRatio");
6452   ret->synchronizeTimeWithSupport();
6453   return ret.retn();
6454 }
6455
6456 /*!
6457  * Creates a new MEDCouplingFieldDouble holding Aspect Ratio values of all
6458  * cells. Currently cells of the following types are treated:
6459  * INTERP_KERNEL::NORM_TRI3, INTERP_KERNEL::NORM_QUAD4 and INTERP_KERNEL::NORM_TETRA4.
6460  * For a cell of other type an exception is thrown.
6461  * Space dimension of a 2D mesh can be either 2 or 3.
6462  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6463  *          cells and one time, lying on \a this mesh. The caller is to delete this
6464  *          field using decrRef() as it is no more needed. 
6465  *  \throw If the coordinates array is not set.
6466  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6467  *  \throw If the connectivity data array has more than one component.
6468  *  \throw If the connectivity data array has a named component.
6469  *  \throw If the connectivity index data array has more than one component.
6470  *  \throw If the connectivity index data array has a named component.
6471  *  \throw If \a this->getMeshDimension() is neither 2 nor 3.
6472  *  \throw If \a this->getSpaceDimension() is neither 2 nor 3.
6473  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6474  */
6475 MEDCouplingFieldDouble *MEDCouplingUMesh::getAspectRatioField() const
6476 {
6477   checkConsistencyLight();
6478   int spaceDim=getSpaceDimension();
6479   int meshDim=getMeshDimension();
6480   if(spaceDim!=2 && spaceDim!=3)
6481     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : SpaceDimension must be equal to 2 or 3 !");
6482   if(meshDim!=2 && meshDim!=3)
6483     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : MeshDimension must be equal to 2 or 3 !");
6484   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6485   ret->setMesh(this);
6486   int nbOfCells=getNumberOfCells();
6487   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6488   arr->alloc(nbOfCells,1);
6489   double *pt=arr->getPointer();
6490   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6491   const int *conn=_nodal_connec->getConstPointer();
6492   const int *connI=_nodal_connec_index->getConstPointer();
6493   const double *coo=_coords->getConstPointer();
6494   double tmp[12];
6495   for(int i=0;i<nbOfCells;i++,pt++)
6496     {
6497       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6498       switch(t)
6499       {
6500         case INTERP_KERNEL::NORM_TRI3:
6501           {
6502             FillInCompact3DMode(spaceDim,3,conn+1,coo,tmp);
6503             *pt=INTERP_KERNEL::triAspectRatio(tmp);
6504             break;
6505           }
6506         case INTERP_KERNEL::NORM_QUAD4:
6507           {
6508             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6509             *pt=INTERP_KERNEL::quadAspectRatio(tmp);
6510             break;
6511           }
6512         case INTERP_KERNEL::NORM_TETRA4:
6513           {
6514             FillInCompact3DMode(spaceDim,4,conn+1,coo,tmp);
6515             *pt=INTERP_KERNEL::tetraAspectRatio(tmp);
6516             break;
6517           }
6518         default:
6519           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getAspectRatioField : A cell with not manged type (NORM_TRI3, NORM_QUAD4 and NORM_TETRA4) has been detected !");
6520       }
6521       conn+=connI[i+1]-connI[i];
6522     }
6523   ret->setName("AspectRatio");
6524   ret->synchronizeTimeWithSupport();
6525   return ret.retn();
6526 }
6527
6528 /*!
6529  * Creates a new MEDCouplingFieldDouble holding Warping factor values of all
6530  * cells of \a this 2D mesh in 3D space. It is a measure of the "planarity" of 2D cell
6531  * in 3D space. Currently only cells of the following types are
6532  * treated: INTERP_KERNEL::NORM_QUAD4.
6533  * For a cell of other type an exception is thrown.
6534  * The warp field is computed as follows: let (a,b,c,d) be the points of the quad.
6535  * Defining
6536  * \f$t=\vec{da}\times\vec{ab}\f$,
6537  * \f$u=\vec{ab}\times\vec{bc}\f$
6538  * \f$v=\vec{bc}\times\vec{cd}\f$
6539  * \f$w=\vec{cd}\times\vec{da}\f$, the warp is defined as \f$W^3\f$ with
6540  *  \f[
6541  *     W=min(\frac{t}{|t|}\cdot\frac{v}{|v|}, \frac{u}{|u|}\cdot\frac{w}{|w|})
6542  *  \f]
6543  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6544  *          cells and one time, lying on \a this mesh. The caller is to delete this
6545  *          field using decrRef() as it is no more needed. 
6546  *  \throw If the coordinates array is not set.
6547  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6548  *  \throw If the connectivity data array has more than one component.
6549  *  \throw If the connectivity data array has a named component.
6550  *  \throw If the connectivity index data array has more than one component.
6551  *  \throw If the connectivity index data array has a named component.
6552  *  \throw If \a this->getMeshDimension() != 2.
6553  *  \throw If \a this->getSpaceDimension() != 3.
6554  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6555  */
6556 MEDCouplingFieldDouble *MEDCouplingUMesh::getWarpField() const
6557 {
6558   checkConsistencyLight();
6559   int spaceDim=getSpaceDimension();
6560   int meshDim=getMeshDimension();
6561   if(spaceDim!=3)
6562     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : SpaceDimension must be equal to 3 !");
6563   if(meshDim!=2)
6564     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : MeshDimension must be equal to 2 !");
6565   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6566   ret->setMesh(this);
6567   int nbOfCells=getNumberOfCells();
6568   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6569   arr->alloc(nbOfCells,1);
6570   double *pt=arr->getPointer();
6571   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6572   const int *conn=_nodal_connec->getConstPointer();
6573   const int *connI=_nodal_connec_index->getConstPointer();
6574   const double *coo=_coords->getConstPointer();
6575   double tmp[12];
6576   for(int i=0;i<nbOfCells;i++,pt++)
6577     {
6578       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6579       switch(t)
6580       {
6581         case INTERP_KERNEL::NORM_QUAD4:
6582           {
6583             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6584             *pt=INTERP_KERNEL::quadWarp(tmp);
6585             break;
6586           }
6587         default:
6588           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getWarpField : A cell with not manged type (NORM_QUAD4) has been detected !");
6589       }
6590       conn+=connI[i+1]-connI[i];
6591     }
6592   ret->setName("Warp");
6593   ret->synchronizeTimeWithSupport();
6594   return ret.retn();
6595 }
6596
6597
6598 /*!
6599  * Creates a new MEDCouplingFieldDouble holding Skew factor values of all
6600  * cells of \a this 2D mesh in 3D space. Currently cells of the following types are
6601  * treated: INTERP_KERNEL::NORM_QUAD4.
6602  * The skew is computed as follow for a quad with points (a,b,c,d): let
6603  * \f$u=\vec{ab}+\vec{dc}\f$ and \f$v=\vec{ac}+\vec{bd}\f$
6604  * then the skew is computed as:
6605  *  \f[
6606  *    s=\frac{u}{|u|}\cdot\frac{v}{|v|}
6607  *  \f]
6608  *
6609  * For a cell of other type an exception is thrown.
6610  *  \return MEDCouplingFieldDouble * - a new instance of MEDCouplingFieldDouble on
6611  *          cells and one time, lying on \a this mesh. The caller is to delete this
6612  *          field using decrRef() as it is no more needed. 
6613  *  \throw If the coordinates array is not set.
6614  *  \throw If \a this mesh contains elements of dimension different from the mesh dimension.
6615  *  \throw If the connectivity data array has more than one component.
6616  *  \throw If the connectivity data array has a named component.
6617  *  \throw If the connectivity index data array has more than one component.
6618  *  \throw If the connectivity index data array has a named component.
6619  *  \throw If \a this->getMeshDimension() != 2.
6620  *  \throw If \a this->getSpaceDimension() != 3.
6621  *  \throw If \a this mesh includes cells of type different from the ones enumerated above.
6622  */
6623 MEDCouplingFieldDouble *MEDCouplingUMesh::getSkewField() const
6624 {
6625   checkConsistencyLight();
6626   int spaceDim=getSpaceDimension();
6627   int meshDim=getMeshDimension();
6628   if(spaceDim!=3)
6629     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : SpaceDimension must be equal to 3 !");
6630   if(meshDim!=2)
6631     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : MeshDimension must be equal to 2 !");
6632   MCAuto<MEDCouplingFieldDouble> ret=MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME);
6633   ret->setMesh(this);
6634   int nbOfCells=getNumberOfCells();
6635   MCAuto<DataArrayDouble> arr=DataArrayDouble::New();
6636   arr->alloc(nbOfCells,1);
6637   double *pt=arr->getPointer();
6638   ret->setArray(arr);//In case of throw to avoid mem leaks arr will be used after decrRef.
6639   const int *conn=_nodal_connec->getConstPointer();
6640   const int *connI=_nodal_connec_index->getConstPointer();
6641   const double *coo=_coords->getConstPointer();
6642   double tmp[12];
6643   for(int i=0;i<nbOfCells;i++,pt++)
6644     {
6645       INTERP_KERNEL::NormalizedCellType t=(INTERP_KERNEL::NormalizedCellType)*conn;
6646       switch(t)
6647       {
6648         case INTERP_KERNEL::NORM_QUAD4:
6649           {
6650             FillInCompact3DMode(3,4,conn+1,coo,tmp);
6651             *pt=INTERP_KERNEL::quadSkew(tmp);
6652             break;
6653           }
6654         default:
6655           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::getSkewField : A cell with not manged type (NORM_QUAD4) has been detected !");
6656       }
6657       conn+=connI[i+1]-connI[i];
6658     }
6659   ret->setName("Skew");
6660   ret->synchronizeTimeWithSupport();
6661   return ret.retn();
6662 }
6663
6664 /*!
6665  * 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.
6666  *
6667  * \return a new instance of field containing the result. The returned instance has to be deallocated by the caller.
6668  *
6669  * \sa getSkewField, getWarpField, getAspectRatioField, getEdgeRatioField
6670  */
6671 MEDCouplingFieldDouble *MEDCouplingUMesh::computeDiameterField() const
6672 {
6673   checkConsistencyLight();
6674   MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS,ONE_TIME));
6675   ret->setMesh(this);
6676   std::set<INTERP_KERNEL::NormalizedCellType> types;
6677   ComputeAllTypesInternal(types,_nodal_connec,_nodal_connec_index);
6678   int spaceDim(getSpaceDimension()),nbCells(getNumberOfCells());
6679   MCAuto<DataArrayDouble> arr(DataArrayDouble::New());
6680   arr->alloc(nbCells,1);
6681   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++)
6682     {
6683       INTERP_KERNEL::AutoCppPtr<INTERP_KERNEL::DiameterCalculator> dc(INTERP_KERNEL::CellModel::GetCellModel(*it).buildInstanceOfDiameterCalulator(spaceDim));
6684       MCAuto<DataArrayInt> cellIds(giveCellsWithType(*it));
6685       dc->computeForListOfCellIdsUMeshFrmt(cellIds->begin(),cellIds->end(),_nodal_connec_index->begin(),_nodal_connec->begin(),getCoords()->begin(),arr->getPointer());
6686     }
6687   ret->setArray(arr);
6688   ret->setName("Diameter");
6689   return ret.retn();
6690 }
6691
6692 /*!
6693  * This method aggregate the bbox of each cell and put it into bbox parameter.
6694  * 
6695  * \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)
6696  *                         For all other cases this input parameter is ignored.
6697  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6698  * 
6699  * \throw If \a this is not fully set (coordinates and connectivity).
6700  * \throw If a cell in \a this has no valid nodeId.
6701  * \sa MEDCouplingUMesh::getBoundingBoxForBBTreeFast, MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6702  */
6703 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree(double arcDetEps) const
6704 {
6705   int mDim(getMeshDimension()),sDim(getSpaceDimension());
6706   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.
6707     return getBoundingBoxForBBTreeFast();
6708   if((mDim==2 && sDim==2) || (mDim==1 && sDim==2))
6709     {
6710       bool presenceOfQuadratic(false);
6711       for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator it=_types.begin();it!=_types.end();it++)
6712         {
6713           const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(*it));
6714           if(cm.isQuadratic())
6715             presenceOfQuadratic=true;
6716         }
6717       if(!presenceOfQuadratic)
6718         return getBoundingBoxForBBTreeFast();
6719       if(mDim==2 && sDim==2)
6720         return getBoundingBoxForBBTree2DQuadratic(arcDetEps);
6721       else
6722         return getBoundingBoxForBBTree1DQuadratic(arcDetEps);
6723     }
6724   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) !");
6725 }
6726
6727 /*!
6728  * This method aggregate the bbox of each cell only considering the nodes constituting each cell and put it into bbox parameter.
6729  * So meshes having quadratic cells the computed bounding boxes can be invalid !
6730  * 
6731  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6732  * 
6733  * \throw If \a this is not fully set (coordinates and connectivity).
6734  * \throw If a cell in \a this has no valid nodeId.
6735  */
6736 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTreeFast() const
6737 {
6738   checkFullyDefined();
6739   int spaceDim(getSpaceDimension()),nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
6740   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6741   double *bbox(ret->getPointer());
6742   for(int i=0;i<nbOfCells*spaceDim;i++)
6743     {
6744       bbox[2*i]=std::numeric_limits<double>::max();
6745       bbox[2*i+1]=-std::numeric_limits<double>::max();
6746     }
6747   const double *coordsPtr(_coords->getConstPointer());
6748   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6749   for(int i=0;i<nbOfCells;i++)
6750     {
6751       int offset=connI[i]+1;
6752       int nbOfNodesForCell(connI[i+1]-offset),kk(0);
6753       for(int j=0;j<nbOfNodesForCell;j++)
6754         {
6755           int nodeId=conn[offset+j];
6756           if(nodeId>=0 && nodeId<nbOfNodes)
6757             {
6758               for(int k=0;k<spaceDim;k++)
6759                 {
6760                   bbox[2*spaceDim*i+2*k]=std::min(bbox[2*spaceDim*i+2*k],coordsPtr[spaceDim*nodeId+k]);
6761                   bbox[2*spaceDim*i+2*k+1]=std::max(bbox[2*spaceDim*i+2*k+1],coordsPtr[spaceDim*nodeId+k]);
6762                 }
6763               kk++;
6764             }
6765         }
6766       if(kk==0)
6767         {
6768           std::ostringstream oss; oss << "MEDCouplingUMesh::getBoundingBoxForBBTree : cell #" << i << " contains no valid nodeId !";
6769           throw INTERP_KERNEL::Exception(oss.str().c_str());
6770         }
6771     }
6772   return ret.retn();
6773 }
6774
6775 /*!
6776  * This method aggregates the bbox of each 2D cell in \a this considering the whole shape. This method is particularly
6777  * useful for 2D meshes having quadratic cells
6778  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6779  * the two extremities of the arc of circle).
6780  * 
6781  * \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)
6782  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6783  * \throw If \a this is not fully defined.
6784  * \throw If \a this is not a mesh with meshDimension equal to 2.
6785  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6786  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic
6787  */
6788 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic(double arcDetEps) const
6789 {
6790   checkFullyDefined();
6791   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6792   if(spaceDim!=2 || mDim!=2)
6793     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!");
6794   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6795   double *bbox(ret->getPointer());
6796   const double *coords(_coords->getConstPointer());
6797   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6798   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6799     {
6800       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6801       int sz(connI[1]-connI[0]-1);
6802       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6803       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6804       INTERP_KERNEL::QuadraticPolygon *pol(0);
6805       for(int j=0;j<sz;j++)
6806         {
6807           int nodeId(conn[*connI+1+j]);
6808           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6809         }
6810       if(!cm.isQuadratic())
6811         pol=INTERP_KERNEL::QuadraticPolygon::BuildLinearPolygon(nodes);
6812       else
6813         pol=INTERP_KERNEL::QuadraticPolygon::BuildArcCirclePolygon(nodes);
6814       INTERP_KERNEL::Bounds b; b.prepareForAggregation(); pol->fillBounds(b); delete pol;
6815       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); 
6816     }
6817   return ret.retn();
6818 }
6819
6820 /*!
6821  * This method aggregates the bbox of each 1D cell in \a this considering the whole shape. This method is particularly
6822  * useful for 2D meshes having quadratic cells
6823  * because for this type of cells getBoundingBoxForBBTreeFast method may return invalid bounding boxes (since it just considers
6824  * the two extremities of the arc of circle).
6825  * 
6826  * \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)
6827  * \return DataArrayDouble * - newly created object (to be managed by the caller) \a this number of cells tuples and 2*spacedim components.
6828  * \throw If \a this is not fully defined.
6829  * \throw If \a this is not a mesh with meshDimension equal to 1.
6830  * \throw If \a this is not a mesh with spaceDimension equal to 2.
6831  * \sa MEDCouplingUMesh::getBoundingBoxForBBTree2DQuadratic
6832  */
6833 DataArrayDouble *MEDCouplingUMesh::getBoundingBoxForBBTree1DQuadratic(double arcDetEps) const
6834 {
6835   checkFullyDefined();
6836   int spaceDim(getSpaceDimension()),mDim(getMeshDimension()),nbOfCells(getNumberOfCells());
6837   if(spaceDim!=2 || mDim!=1)
6838     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!");
6839   MCAuto<DataArrayDouble> ret(DataArrayDouble::New()); ret->alloc(nbOfCells,2*spaceDim);
6840   double *bbox(ret->getPointer());
6841   const double *coords(_coords->getConstPointer());
6842   const int *conn(_nodal_connec->getConstPointer()),*connI(_nodal_connec_index->getConstPointer());
6843   for(int i=0;i<nbOfCells;i++,bbox+=4,connI++)
6844     {
6845       const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*connI]));
6846       int sz(connI[1]-connI[0]-1);
6847       INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=arcDetEps;
6848       std::vector<INTERP_KERNEL::Node *> nodes(sz);
6849       INTERP_KERNEL::Edge *edge(0);
6850       for(int j=0;j<sz;j++)
6851         {
6852           int nodeId(conn[*connI+1+j]);
6853           nodes[j]=new INTERP_KERNEL::Node(coords[nodeId*2],coords[nodeId*2+1]);
6854         }
6855       if(!cm.isQuadratic())
6856         edge=INTERP_KERNEL::QuadraticPolygon::BuildLinearEdge(nodes);
6857       else
6858         edge=INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(nodes);
6859       const INTERP_KERNEL::Bounds& b(edge->getBounds());
6860       bbox[0]=b.getXMin(); bbox[1]=b.getXMax(); bbox[2]=b.getYMin(); bbox[3]=b.getYMax(); edge->decrRef();
6861     }
6862   return ret.retn();
6863 }
6864
6865 /// @cond INTERNAL
6866
6867 namespace MEDCouplingImpl
6868 {
6869   class ConnReader
6870   {
6871   public:
6872     ConnReader(const int *c, int val):_conn(c),_val(val) { }
6873     bool operator() (const int& pos) { return _conn[pos]!=_val; }
6874   private:
6875     const int *_conn;
6876     int _val;
6877   };
6878
6879   class ConnReader2
6880   {
6881   public:
6882     ConnReader2(const int *c, int val):_conn(c),_val(val) { }
6883     bool operator() (const int& pos) { return _conn[pos]==_val; }
6884   private:
6885     const int *_conn;
6886     int _val;
6887   };
6888 }
6889
6890 /// @endcond
6891
6892 /*!
6893  * This method expects that \a this is sorted by types. If not an exception will be thrown.
6894  * This method returns in the same format as code (see MEDCouplingUMesh::checkTypeConsistencyAndContig or MEDCouplingUMesh::splitProfilePerType) how
6895  * \a this is composed in cell types.
6896  * The returned array is of size 3*n where n is the number of different types present in \a this. 
6897  * For every k in [0,n] ret[3*k+2]==-1 because it has no sense here. 
6898  * This parameter is kept only for compatibility with other methode listed above.
6899  */
6900 std::vector<int> MEDCouplingUMesh::getDistributionOfTypes() const
6901 {
6902   checkConnectivityFullyDefined();
6903   const int *conn=_nodal_connec->getConstPointer();
6904   const int *connI=_nodal_connec_index->getConstPointer();
6905   const int *work=connI;
6906   int nbOfCells=getNumberOfCells();
6907   std::size_t n=getAllGeoTypes().size();
6908   std::vector<int> ret(3*n,-1); //ret[3*k+2]==-1 because it has no sense here
6909   std::set<INTERP_KERNEL::NormalizedCellType> types;
6910   for(std::size_t i=0;work!=connI+nbOfCells;i++)
6911     {
6912       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn[*work];
6913       if(types.find(typ)!=types.end())
6914         {
6915           std::ostringstream oss; oss << "MEDCouplingUMesh::getDistributionOfTypes : Type " << INTERP_KERNEL::CellModel::GetCellModel(typ).getRepr();
6916           oss << " is not contiguous !";
6917           throw INTERP_KERNEL::Exception(oss.str().c_str());
6918         }
6919       types.insert(typ);
6920       ret[3*i]=typ;
6921       const int *work2=std::find_if(work+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,typ));
6922       ret[3*i+1]=(int)std::distance(work,work2);
6923       work=work2;
6924     }
6925   return ret;
6926 }
6927
6928 /*!
6929  * This method is used to check that this has contiguous cell type in same order than described in \a code.
6930  * only for types cell, type node is not managed.
6931  * Format of \a code is the following. \a code should be of size 3*n and non empty. If not an exception is thrown.
6932  * foreach k in [0,n) on 3*k pos represent the geometric type and 3*k+1 number of elements of type 3*k.
6933  * 3*k+2 refers if different from -1 the pos in 'idsPerType' to get the corresponding array.
6934  * If 2 or more same geometric type is in \a code and exception is thrown too.
6935  *
6936  * This method firstly checks
6937  * If it exists k so that 3*k geometric type is not in geometric types of this an exception will be thrown.
6938  * If it exists k so that 3*k geometric type exists but the number of consecutive cell types does not match,
6939  * an exception is thrown too.
6940  * 
6941  * If all geometric types in \a code are exactly those in \a this null pointer is returned.
6942  * If it exists a geometric type in \a this \b not in \a code \b no exception is thrown 
6943  * and a DataArrayInt instance is returned that the user has the responsability to deallocate.
6944  */
6945 DataArrayInt *MEDCouplingUMesh::checkTypeConsistencyAndContig(const std::vector<int>& code, const std::vector<const DataArrayInt *>& idsPerType) const
6946 {
6947   if(code.empty())
6948     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code is empty, should not !");
6949   std::size_t sz=code.size();
6950   std::size_t n=sz/3;
6951   if(sz%3!=0)
6952     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code size is NOT %3 !");
6953   std::vector<INTERP_KERNEL::NormalizedCellType> types;
6954   int nb=0;
6955   bool isNoPflUsed=true;
6956   for(std::size_t i=0;i<n;i++)
6957     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)code[3*i])==types.end())
6958       {
6959         types.push_back((INTERP_KERNEL::NormalizedCellType)code[3*i]);
6960         nb+=code[3*i+1];
6961         if(_types.find((INTERP_KERNEL::NormalizedCellType)code[3*i])==_types.end())
6962           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : expected geo types not in this !");
6963         isNoPflUsed=isNoPflUsed && (code[3*i+2]==-1);
6964       }
6965   if(types.size()!=n)
6966     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : code contains duplication of types in unstructured mesh !");
6967   if(isNoPflUsed)
6968     {
6969       if(!checkConsecutiveCellTypesAndOrder(&types[0],&types[0]+types.size()))
6970         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : non contiguous type !");
6971       if(types.size()==_types.size())
6972         return 0;
6973     }
6974   MCAuto<DataArrayInt> ret=DataArrayInt::New();
6975   ret->alloc(nb,1);
6976   int *retPtr=ret->getPointer();
6977   const int *connI=_nodal_connec_index->getConstPointer();
6978   const int *conn=_nodal_connec->getConstPointer();
6979   int nbOfCells=getNumberOfCells();
6980   const int *i=connI;
6981   int kk=0;
6982   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator it=types.begin();it!=types.end();it++,kk++)
6983     {
6984       i=std::find_if(i,connI+nbOfCells,MEDCouplingImpl::ConnReader2(conn,(int)(*it)));
6985       int offset=(int)std::distance(connI,i);
6986       const int *j=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)(*it)));
6987       int nbOfCellsOfCurType=(int)std::distance(i,j);
6988       if(code[3*kk+2]==-1)
6989         for(int k=0;k<nbOfCellsOfCurType;k++)
6990           *retPtr++=k+offset;
6991       else
6992         {
6993           int idInIdsPerType=code[3*kk+2];
6994           if(idInIdsPerType>=0 && idInIdsPerType<(int)idsPerType.size())
6995             {
6996               const DataArrayInt *zePfl=idsPerType[idInIdsPerType];
6997               if(zePfl)
6998                 {
6999                   zePfl->checkAllocated();
7000                   if(zePfl->getNumberOfComponents()==1)
7001                     {
7002                       for(const int *k=zePfl->begin();k!=zePfl->end();k++,retPtr++)
7003                         {
7004                           if(*k>=0 && *k<nbOfCellsOfCurType)
7005                             *retPtr=(*k)+offset;
7006                           else
7007                             {
7008                               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : the section " << kk << " points to the profile #" << idInIdsPerType;
7009                               oss << ", and this profile contains a value " << *k << " should be in [0," << nbOfCellsOfCurType << ") !";
7010                               throw INTERP_KERNEL::Exception(oss.str().c_str());
7011                             }
7012                         }
7013                     }
7014                   else
7015                     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of a profile with nb of compo != 1 !");
7016                 }
7017               else
7018                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::checkTypeConsistencyAndContig : presence of null profile !");
7019             }
7020           else
7021             {
7022               std::ostringstream oss; oss << "MEDCouplingUMesh::checkTypeConsistencyAndContig : at section " << kk << " of code it points to the array #" << idInIdsPerType;
7023               oss << " should be in [0," << idsPerType.size() << ") !";
7024               throw INTERP_KERNEL::Exception(oss.str().c_str());
7025             }
7026         }
7027       i=j;
7028     }
7029   return ret.retn();
7030 }
7031
7032 /*!
7033  * This method makes the hypothesis that \a this is sorted by type. If not an exception will be thrown.
7034  * 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.
7035  * 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.
7036  * This method has 1 input \a profile and 3 outputs \a code \a idsInPflPerType and \a idsPerType.
7037  * 
7038  * \param [in] profile
7039  * \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.
7040  * \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,
7041  *              \a idsInPflPerType[i] stores the tuple ids in \a profile that correspond to the geometric type code[3*i+0]
7042  * \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.
7043  *              This vector can be empty in case of all geometric type cells are fully covered in ascending in the given input \a profile.
7044  * \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
7045  */
7046 void MEDCouplingUMesh::splitProfilePerType(const DataArrayInt *profile, std::vector<int>& code, std::vector<DataArrayInt *>& idsInPflPerType, std::vector<DataArrayInt *>& idsPerType) const
7047 {
7048   if(!profile)
7049     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile is NULL !");
7050   if(profile->getNumberOfComponents()!=1)
7051     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : input profile should have exactly one component !");
7052   checkConnectivityFullyDefined();
7053   const int *conn=_nodal_connec->getConstPointer();
7054   const int *connI=_nodal_connec_index->getConstPointer();
7055   int nbOfCells=getNumberOfCells();
7056   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7057   std::vector<int> typeRangeVals(1);
7058   for(const int *i=connI;i!=connI+nbOfCells;)
7059     {
7060       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7061       if(std::find(types.begin(),types.end(),curType)!=types.end())
7062         {
7063           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::splitProfilePerType : current mesh is not sorted by type !");
7064         }
7065       types.push_back(curType);
7066       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7067       typeRangeVals.push_back((int)std::distance(connI,i));
7068     }
7069   //
7070   DataArrayInt *castArr=0,*rankInsideCast=0,*castsPresent=0;
7071   profile->splitByValueRange(&typeRangeVals[0],&typeRangeVals[0]+typeRangeVals.size(),castArr,rankInsideCast,castsPresent);
7072   MCAuto<DataArrayInt> tmp0=castArr;
7073   MCAuto<DataArrayInt> tmp1=rankInsideCast;
7074   MCAuto<DataArrayInt> tmp2=castsPresent;
7075   //
7076   int nbOfCastsFinal=castsPresent->getNumberOfTuples();
7077   code.resize(3*nbOfCastsFinal);
7078   std::vector< MCAuto<DataArrayInt> > idsInPflPerType2;
7079   std::vector< MCAuto<DataArrayInt> > idsPerType2;
7080   for(int i=0;i<nbOfCastsFinal;i++)
7081     {
7082       int castId=castsPresent->getIJ(i,0);
7083       MCAuto<DataArrayInt> tmp3=castArr->findIdsEqual(castId);
7084       idsInPflPerType2.push_back(tmp3);
7085       code[3*i]=(int)types[castId];
7086       code[3*i+1]=tmp3->getNumberOfTuples();
7087       MCAuto<DataArrayInt> tmp4=rankInsideCast->selectByTupleId(tmp3->getConstPointer(),tmp3->getConstPointer()+tmp3->getNumberOfTuples());
7088       if(!tmp4->isIota(typeRangeVals[castId+1]-typeRangeVals[castId]))
7089         {
7090           tmp4->copyStringInfoFrom(*profile);
7091           idsPerType2.push_back(tmp4);
7092           code[3*i+2]=(int)idsPerType2.size()-1;
7093         }
7094       else
7095         {
7096           code[3*i+2]=-1;
7097         }
7098     }
7099   std::size_t sz2=idsInPflPerType2.size();
7100   idsInPflPerType.resize(sz2);
7101   for(std::size_t i=0;i<sz2;i++)
7102     {
7103       DataArrayInt *locDa=idsInPflPerType2[i];
7104       locDa->incrRef();
7105       idsInPflPerType[i]=locDa;
7106     }
7107   std::size_t sz=idsPerType2.size();
7108   idsPerType.resize(sz);
7109   for(std::size_t i=0;i<sz;i++)
7110     {
7111       DataArrayInt *locDa=idsPerType2[i];
7112       locDa->incrRef();
7113       idsPerType[i]=locDa;
7114     }
7115 }
7116
7117 /*!
7118  * This method is here too emulate the MEDMEM behaviour on BDC (buildDescendingConnectivity). Hoping this method becomes deprecated very soon.
7119  * This method make the assumption that \a this and 'nM1LevMesh' mesh lyies on same coords (same pointer) as MED and MEDMEM does.
7120  * The following equality should be verified 'nM1LevMesh->getMeshDimension()==this->getMeshDimension()-1'
7121  * 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.
7122  */
7123 MEDCouplingUMesh *MEDCouplingUMesh::emulateMEDMEMBDC(const MEDCouplingUMesh *nM1LevMesh, DataArrayInt *desc, DataArrayInt *descIndx, DataArrayInt *&revDesc, DataArrayInt *&revDescIndx, DataArrayInt *& nM1LevMeshIds, DataArrayInt *&meshnM1Old2New) const
7124 {
7125   checkFullyDefined();
7126   nM1LevMesh->checkFullyDefined();
7127   if(getMeshDimension()-1!=nM1LevMesh->getMeshDimension())
7128     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : The mesh passed as first argument should have a meshDim equal to this->getMeshDimension()-1 !" );
7129   if(_coords!=nM1LevMesh->getCoords())
7130     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::emulateMEDMEMBDC : 'this' and mesh in first argument should share the same coords : Use tryToShareSameCoords method !");
7131   MCAuto<DataArrayInt> tmp0=DataArrayInt::New();
7132   MCAuto<DataArrayInt> tmp1=DataArrayInt::New();
7133   MCAuto<MEDCouplingUMesh> ret1=buildDescendingConnectivity(desc,descIndx,tmp0,tmp1);
7134   MCAuto<DataArrayInt> ret0=ret1->sortCellsInMEDFileFrmt();
7135   desc->transformWithIndArr(ret0->getConstPointer(),ret0->getConstPointer()+ret0->getNbOfElems());
7136   MCAuto<MEDCouplingUMesh> tmp=MEDCouplingUMesh::New();
7137   tmp->setConnectivity(tmp0,tmp1);
7138   tmp->renumberCells(ret0->getConstPointer(),false);
7139   revDesc=tmp->getNodalConnectivity();
7140   revDescIndx=tmp->getNodalConnectivityIndex();
7141   DataArrayInt *ret=0;
7142   if(!ret1->areCellsIncludedIn(nM1LevMesh,2,ret))
7143     {
7144       int tmp2;
7145       ret->getMaxValue(tmp2);
7146       ret->decrRef();
7147       std::ostringstream oss; oss << "MEDCouplingUMesh::emulateMEDMEMBDC : input N-1 mesh present a cell not in descending mesh ... Id of cell is " << tmp2 << " !";
7148       throw INTERP_KERNEL::Exception(oss.str().c_str());
7149     }
7150   nM1LevMeshIds=ret;
7151   //
7152   revDesc->incrRef();
7153   revDescIndx->incrRef();
7154   ret1->incrRef();
7155   ret0->incrRef();
7156   meshnM1Old2New=ret0;
7157   return ret1;
7158 }
7159
7160 /*!
7161  * Permutes the nodal connectivity arrays so that the cells are sorted by type, which is
7162  * necessary for writing the mesh to MED file. Additionally returns a permutation array
7163  * in "Old to New" mode.
7164  *  \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete
7165  *          this array using decrRef() as it is no more needed.
7166  *  \throw If the nodal connectivity of cells is not defined.
7167  */
7168 DataArrayInt *MEDCouplingUMesh::sortCellsInMEDFileFrmt()
7169 {
7170   checkConnectivityFullyDefined();
7171   MCAuto<DataArrayInt> ret=getRenumArrForMEDFileFrmt();
7172   renumberCells(ret->getConstPointer(),false);
7173   return ret.retn();
7174 }
7175
7176 /*!
7177  * This methods checks that cells are sorted by their types.
7178  * This method makes asumption (no check) that connectivity is correctly set before calling.
7179  */
7180 bool MEDCouplingUMesh::checkConsecutiveCellTypes() const
7181 {
7182   checkFullyDefined();
7183   const int *conn=_nodal_connec->getConstPointer();
7184   const int *connI=_nodal_connec_index->getConstPointer();
7185   int nbOfCells=getNumberOfCells();
7186   std::set<INTERP_KERNEL::NormalizedCellType> types;
7187   for(const int *i=connI;i!=connI+nbOfCells;)
7188     {
7189       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7190       if(types.find(curType)!=types.end())
7191         return false;
7192       types.insert(curType);
7193       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7194     }
7195   return true;
7196 }
7197
7198 /*!
7199  * This method is a specialization of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder method that is called here.
7200  * The geometric type order is specified by MED file.
7201  * 
7202  * \sa  MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder
7203  */
7204 bool MEDCouplingUMesh::checkConsecutiveCellTypesForMEDFileFrmt() const
7205 {
7206   return checkConsecutiveCellTypesAndOrder(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7207 }
7208
7209 /*!
7210  * This method performs the same job as checkConsecutiveCellTypes except that the order of types sequence is analyzed to check
7211  * that the order is specified in array defined by [ \a orderBg , \a orderEnd ).
7212  * If there is some geo types in \a this \b NOT in [ \a orderBg, \a orderEnd ) it is OK (return true) if contiguous.
7213  * If there is some geo types in [ \a orderBg, \a orderEnd ) \b NOT in \a this it is OK too (return true) if contiguous.
7214  */
7215 bool MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7216 {
7217   checkFullyDefined();
7218   const int *conn=_nodal_connec->getConstPointer();
7219   const int *connI=_nodal_connec_index->getConstPointer();
7220   int nbOfCells=getNumberOfCells();
7221   if(nbOfCells==0)
7222     return true;
7223   int lastPos=-1;
7224   std::set<INTERP_KERNEL::NormalizedCellType> sg;
7225   for(const int *i=connI;i!=connI+nbOfCells;)
7226     {
7227       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7228       const INTERP_KERNEL::NormalizedCellType *isTypeExists=std::find(orderBg,orderEnd,curType);
7229       if(isTypeExists!=orderEnd)
7230         {
7231           int pos=(int)std::distance(orderBg,isTypeExists);
7232           if(pos<=lastPos)
7233             return false;
7234           lastPos=pos;
7235           i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7236         }
7237       else
7238         {
7239           if(sg.find(curType)==sg.end())
7240             {
7241               i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7242               sg.insert(curType);
7243             }
7244           else
7245             return false;
7246         }
7247     }
7248   return true;
7249 }
7250
7251 /*!
7252  * This method returns 2 newly allocated DataArrayInt instances. The first is an array of size 'this->getNumberOfCells()' with one component,
7253  * 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
7254  * 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'.
7255  */
7256 DataArrayInt *MEDCouplingUMesh::getLevArrPerCellTypes(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd, DataArrayInt *&nbPerType) const
7257 {
7258   checkConnectivityFullyDefined();
7259   int nbOfCells=getNumberOfCells();
7260   const int *conn=_nodal_connec->getConstPointer();
7261   const int *connI=_nodal_connec_index->getConstPointer();
7262   MCAuto<DataArrayInt> tmpa=DataArrayInt::New();
7263   MCAuto<DataArrayInt> tmpb=DataArrayInt::New();
7264   tmpa->alloc(nbOfCells,1);
7265   tmpb->alloc((int)std::distance(orderBg,orderEnd),1);
7266   tmpb->fillWithZero();
7267   int *tmp=tmpa->getPointer();
7268   int *tmp2=tmpb->getPointer();
7269   for(const int *i=connI;i!=connI+nbOfCells;i++)
7270     {
7271       const INTERP_KERNEL::NormalizedCellType *where=std::find(orderBg,orderEnd,(INTERP_KERNEL::NormalizedCellType)conn[*i]);
7272       if(where!=orderEnd)
7273         {
7274           int pos=(int)std::distance(orderBg,where);
7275           tmp2[pos]++;
7276           tmp[std::distance(connI,i)]=pos;
7277         }
7278       else
7279         {
7280           const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)conn[*i]);
7281           std::ostringstream oss; oss << "MEDCouplingUMesh::getLevArrPerCellTypes : Cell #" << std::distance(connI,i);
7282           oss << " has a type " << cm.getRepr() << " not in input array of type !";
7283           throw INTERP_KERNEL::Exception(oss.str().c_str());
7284         }
7285     }
7286   nbPerType=tmpb.retn();
7287   return tmpa.retn();
7288 }
7289
7290 /*!
7291  * This method behaves exactly as MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec but the order is those defined in MED file spec.
7292  *
7293  * \return a new object containing the old to new correspondance.
7294  *
7295  * \sa MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec, MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7296  */
7297 DataArrayInt *MEDCouplingUMesh::getRenumArrForMEDFileFrmt() const
7298 {
7299   return getRenumArrForConsecutiveCellTypesSpec(MEDMEM_ORDER,MEDMEM_ORDER+N_MEDMEM_ORDER);
7300 }
7301
7302 /*!
7303  * 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.
7304  * This method returns an array of size getNumberOfCells() that gives a renumber array old2New that can be used as input of MEDCouplingMesh::renumberCells.
7305  * The mesh after this call to MEDCouplingMesh::renumberCells will pass the test of MEDCouplingUMesh::checkConsecutiveCellTypesAndOrder with the same inputs.
7306  * The returned array minimizes the permutations that is to say the order of cells inside same geometric type remains the same.
7307  */
7308 DataArrayInt *MEDCouplingUMesh::getRenumArrForConsecutiveCellTypesSpec(const INTERP_KERNEL::NormalizedCellType *orderBg, const INTERP_KERNEL::NormalizedCellType *orderEnd) const
7309 {
7310   DataArrayInt *nbPerType=0;
7311   MCAuto<DataArrayInt> tmpa=getLevArrPerCellTypes(orderBg,orderEnd,nbPerType);
7312   nbPerType->decrRef();
7313   return tmpa->buildPermArrPerLevel();
7314 }
7315
7316 /*!
7317  * This method reorganize the cells of \a this so that the cells with same geometric types are put together.
7318  * The number of cells remains unchanged after the call of this method.
7319  * This method tries to minimizes the number of needed permutations. So, this method behaves not exactly as
7320  * MEDCouplingUMesh::sortCellsInMEDFileFrmt.
7321  *
7322  * \return the array giving the correspondance old to new.
7323  */
7324 DataArrayInt *MEDCouplingUMesh::rearrange2ConsecutiveCellTypes()
7325 {
7326   checkFullyDefined();
7327   computeTypes();
7328   const int *conn=_nodal_connec->getConstPointer();
7329   const int *connI=_nodal_connec_index->getConstPointer();
7330   int nbOfCells=getNumberOfCells();
7331   std::vector<INTERP_KERNEL::NormalizedCellType> types;
7332   for(const int *i=connI;i!=connI+nbOfCells && (types.size()!=_types.size());)
7333     if(std::find(types.begin(),types.end(),(INTERP_KERNEL::NormalizedCellType)conn[*i])==types.end())
7334       {
7335         INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7336         types.push_back(curType);
7337         for(i++;i!=connI+nbOfCells && (INTERP_KERNEL::NormalizedCellType)conn[*i]==curType;i++);
7338       }
7339   DataArrayInt *ret=DataArrayInt::New();
7340   ret->alloc(nbOfCells,1);
7341   int *retPtr=ret->getPointer();
7342   std::fill(retPtr,retPtr+nbOfCells,-1);
7343   int newCellId=0;
7344   for(std::vector<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7345     {
7346       for(const int *i=connI;i!=connI+nbOfCells;i++)
7347         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7348           retPtr[std::distance(connI,i)]=newCellId++;
7349     }
7350   renumberCells(retPtr,false);
7351   return ret;
7352 }
7353
7354 /*!
7355  * This method splits \a this into as mush as untructured meshes that consecutive set of same type cells.
7356  * So this method has typically a sense if MEDCouplingUMesh::checkConsecutiveCellTypes has a sense.
7357  * This method makes asumption that connectivity is correctly set before calling.
7358  */
7359 std::vector<MEDCouplingUMesh *> MEDCouplingUMesh::splitByType() const
7360 {
7361   checkConnectivityFullyDefined();
7362   const int *conn=_nodal_connec->getConstPointer();
7363   const int *connI=_nodal_connec_index->getConstPointer();
7364   int nbOfCells=getNumberOfCells();
7365   std::vector<MEDCouplingUMesh *> ret;
7366   for(const int *i=connI;i!=connI+nbOfCells;)
7367     {
7368       INTERP_KERNEL::NormalizedCellType curType=(INTERP_KERNEL::NormalizedCellType)conn[*i];
7369       int beginCellId=(int)std::distance(connI,i);
7370       i=std::find_if(i+1,connI+nbOfCells,MEDCouplingImpl::ConnReader(conn,(int)curType));
7371       int endCellId=(int)std::distance(connI,i);
7372       int sz=endCellId-beginCellId;
7373       int *cells=new int[sz];
7374       for(int j=0;j<sz;j++)
7375         cells[j]=beginCellId+j;
7376       MEDCouplingUMesh *m=(MEDCouplingUMesh *)buildPartOfMySelf(cells,cells+sz,true);
7377       delete [] cells;
7378       ret.push_back(m);
7379     }
7380   return ret;
7381 }
7382
7383 /*!
7384  * This method performs the opposite operation than those in MEDCoupling1SGTUMesh::buildUnstructured.
7385  * If \a this is a single geometric type unstructured mesh, it will be converted into a more compact data structure,
7386  * MEDCoupling1GTUMesh instance. The returned instance will aggregate the same DataArrayDouble instance of coordinates than \a this.
7387  *
7388  * \return a newly allocated instance, that the caller must manage.
7389  * \throw If \a this contains more than one geometric type.
7390  * \throw If the nodal connectivity of \a this is not fully defined.
7391  * \throw If the internal data is not coherent.
7392  */
7393 MEDCoupling1GTUMesh *MEDCouplingUMesh::convertIntoSingleGeoTypeMesh() const
7394 {
7395   checkConnectivityFullyDefined();
7396   if(_types.size()!=1)
7397     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7398   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7399   MCAuto<MEDCoupling1GTUMesh> ret=MEDCoupling1GTUMesh::New(getName(),typ);
7400   ret->setCoords(getCoords());
7401   MEDCoupling1SGTUMesh *retC=dynamic_cast<MEDCoupling1SGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7402   if(retC)
7403     {
7404       MCAuto<DataArrayInt> c=convertNodalConnectivityToStaticGeoTypeMesh();
7405       retC->setNodalConnectivity(c);
7406     }
7407   else
7408     {
7409       MEDCoupling1DGTUMesh *retD=dynamic_cast<MEDCoupling1DGTUMesh *>((MEDCoupling1GTUMesh*)ret);
7410       if(!retD)
7411         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertIntoSingleGeoTypeMesh : Internal error !");
7412       DataArrayInt *c=0,*ci=0;
7413       convertNodalConnectivityToDynamicGeoTypeMesh(c,ci);
7414       MCAuto<DataArrayInt> cs(c),cis(ci);
7415       retD->setNodalConnectivity(cs,cis);
7416     }
7417   return ret.retn();
7418 }
7419
7420 DataArrayInt *MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh() const
7421 {
7422   checkConnectivityFullyDefined();
7423   if(_types.size()!=1)
7424     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7425   INTERP_KERNEL::NormalizedCellType typ=*_types.begin();
7426   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7427   if(cm.isDynamic())
7428     {
7429       std::ostringstream oss; oss << "MEDCouplingUMesh::convertNodalConnectivityToStaticGeoTypeMesh : this contains a single geo type (" << cm.getRepr() << ") but ";
7430       oss << "this type is dynamic ! Only static geometric type is possible for that type ! call convertNodalConnectivityToDynamicGeoTypeMesh instead !";
7431       throw INTERP_KERNEL::Exception(oss.str().c_str());
7432     }
7433   int nbCells=getNumberOfCells();
7434   int typi=(int)typ;
7435   int nbNodesPerCell=(int)cm.getNumberOfNodes();
7436   MCAuto<DataArrayInt> connOut=DataArrayInt::New(); connOut->alloc(nbCells*nbNodesPerCell,1);
7437   int *outPtr=connOut->getPointer();
7438   const int *conn=_nodal_connec->begin();
7439   const int *connI=_nodal_connec_index->begin();
7440   nbNodesPerCell++;
7441   for(int i=0;i<nbCells;i++,connI++)
7442     {
7443       if(conn[connI[0]]==typi && connI[1]-connI[0]==nbNodesPerCell)
7444         outPtr=std::copy(conn+connI[0]+1,conn+connI[1],outPtr);
7445       else
7446         {
7447           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 << ") !";
7448           throw INTERP_KERNEL::Exception(oss.str().c_str());
7449         }
7450     }
7451   return connOut.retn();
7452 }
7453
7454 /*!
7455  * Convert the nodal connectivity of the mesh so that all the cells are of dynamic types (polygon or quadratic
7456  * polygon). This returns the corresponding new nodal connectivity in \ref numbering-indirect format.
7457  * \param nodalConn
7458  * \param nodalConnI
7459  */
7460 void MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh(DataArrayInt *&nodalConn, DataArrayInt *&nodalConnIndex) const
7461 {
7462   static const char msg0[]="MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : nodal connectivity in this are invalid ! Call checkConsistency !";
7463   checkConnectivityFullyDefined();
7464   if(_types.size()!=1)
7465     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::convertNodalConnectivityToDynamicGeoTypeMesh : current mesh does not contain exactly one geometric type !");
7466   int nbCells=getNumberOfCells(),lgth=_nodal_connec->getNumberOfTuples();
7467   if(lgth<nbCells)
7468     throw INTERP_KERNEL::Exception(msg0);
7469   MCAuto<DataArrayInt> c(DataArrayInt::New()),ci(DataArrayInt::New());
7470   c->alloc(lgth-nbCells,1); ci->alloc(nbCells+1,1);
7471   int *cp(c->getPointer()),*cip(ci->getPointer());
7472   const int *incp(_nodal_connec->begin()),*incip(_nodal_connec_index->begin());
7473   cip[0]=0;
7474   for(int i=0;i<nbCells;i++,cip++,incip++)
7475     {
7476       int strt(incip[0]+1),stop(incip[1]);//+1 to skip geo type
7477       int delta(stop-strt);
7478       if(delta>=1)
7479         {
7480           if((strt>=0 && strt<lgth) && (stop>=0 && stop<=lgth))
7481             cp=std::copy(incp+strt,incp+stop,cp);
7482           else
7483             throw INTERP_KERNEL::Exception(msg0);
7484         }
7485       else
7486         throw INTERP_KERNEL::Exception(msg0);
7487       cip[1]=cip[0]+delta;
7488     }
7489   nodalConn=c.retn(); nodalConnIndex=ci.retn();
7490 }
7491
7492 /*!
7493  * This method takes in input a vector of MEDCouplingUMesh instances lying on the same coordinates with same mesh dimensions.
7494  * Each mesh in \b ms must be sorted by type with the same order (typically using MEDCouplingUMesh::sortCellsInMEDFileFrmt).
7495  * This method is particulary useful for MED file interaction. It allows to aggregate several meshes and keeping the type sorting
7496  * and the track of the permutation by chunk of same geotype cells to retrieve it. The traditional formats old2new and new2old
7497  * are not used here to avoid the build of big permutation array.
7498  *
7499  * \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
7500  *                those specified in MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7501  * \param [out] szOfCellGrpOfSameType is a newly allocated DataArrayInt instance whose number of tuples is equal to the number of chunks of same geotype
7502  *              in all meshes in \b ms. The accumulation of all values of this array is equal to the number of cells of returned mesh.
7503  * \param [out] idInMsOfCellGrpOfSameType is a newly allocated DataArrayInt instance having the same size than \b szOfCellGrpOfSameType. This
7504  *              output array gives for each chunck of same type the corresponding mesh id in \b ms.
7505  * \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
7506  *         is sorted by type following the geo cell types order of MEDCouplingUMesh::sortCellsInMEDFileFrmt method.
7507  */
7508 MEDCouplingUMesh *MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& ms,
7509                                                                             DataArrayInt *&szOfCellGrpOfSameType,
7510                                                                             DataArrayInt *&idInMsOfCellGrpOfSameType)
7511 {
7512   std::vector<const MEDCouplingUMesh *> ms2;
7513   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms.begin();it!=ms.end();it++)
7514     if(*it)
7515       {
7516         (*it)->checkConnectivityFullyDefined();
7517         ms2.push_back(*it);
7518       }
7519   if(ms2.empty())
7520     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : input vector is empty !");
7521   const DataArrayDouble *refCoo=ms2[0]->getCoords();
7522   int meshDim=ms2[0]->getMeshDimension();
7523   std::vector<const MEDCouplingUMesh *> m1ssm;
7524   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmAuto;
7525   //
7526   std::vector<const MEDCouplingUMesh *> m1ssmSingle;
7527   std::vector< MCAuto<MEDCouplingUMesh> > m1ssmSingleAuto;
7528   int fake=0,rk=0;
7529   MCAuto<DataArrayInt> ret1(DataArrayInt::New()),ret2(DataArrayInt::New());
7530   ret1->alloc(0,1); ret2->alloc(0,1);
7531   for(std::vector<const MEDCouplingUMesh *>::const_iterator it=ms2.begin();it!=ms2.end();it++,rk++)
7532     {
7533       if(meshDim!=(*it)->getMeshDimension())
7534         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshdims mismatch !");
7535       if(refCoo!=(*it)->getCoords())
7536         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AggregateSortedByTypeMeshesOnSameCoords : meshes are not shared by a single coordinates coords !");
7537       std::vector<MEDCouplingUMesh *> sp=(*it)->splitByType();
7538       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<const MEDCouplingUMesh *> >(m1ssm));
7539       std::copy(sp.begin(),sp.end(),std::back_insert_iterator< std::vector<MCAuto<MEDCouplingUMesh> > >(m1ssmAuto));
7540       for(std::vector<MEDCouplingUMesh *>::const_iterator it2=sp.begin();it2!=sp.end();it2++)
7541         {
7542           MEDCouplingUMesh *singleCell=static_cast<MEDCouplingUMesh *>((*it2)->buildPartOfMySelf(&fake,&fake+1,true));
7543           m1ssmSingleAuto.push_back(singleCell);
7544           m1ssmSingle.push_back(singleCell);
7545           ret1->pushBackSilent((*it2)->getNumberOfCells()); ret2->pushBackSilent(rk);
7546         }
7547     }
7548   MCAuto<MEDCouplingUMesh> m1ssmSingle2=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmSingle);
7549   MCAuto<DataArrayInt> renum=m1ssmSingle2->sortCellsInMEDFileFrmt();
7550   std::vector<const MEDCouplingUMesh *> m1ssmfinal(m1ssm.size());
7551   for(std::size_t i=0;i<m1ssm.size();i++)
7552     m1ssmfinal[renum->getIJ(i,0)]=m1ssm[i];
7553   MCAuto<MEDCouplingUMesh> ret0=MEDCouplingUMesh::MergeUMeshesOnSameCoords(m1ssmfinal);
7554   szOfCellGrpOfSameType=ret1->renumber(renum->getConstPointer());
7555   idInMsOfCellGrpOfSameType=ret2->renumber(renum->getConstPointer());
7556   return ret0.retn();
7557 }
7558
7559 /*!
7560  * This method returns a newly created DataArrayInt instance.
7561  * This method retrieves cell ids in [ \a begin, \a end ) that have the type \a type.
7562  */
7563 DataArrayInt *MEDCouplingUMesh::keepCellIdsByType(INTERP_KERNEL::NormalizedCellType type, const int *begin, const int *end) const
7564 {
7565   checkFullyDefined();
7566   const int *conn=_nodal_connec->getConstPointer();
7567   const int *connIndex=_nodal_connec_index->getConstPointer();
7568   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
7569   for(const int *w=begin;w!=end;w++)
7570     if((INTERP_KERNEL::NormalizedCellType)conn[connIndex[*w]]==type)
7571       ret->pushBackSilent(*w);
7572   return ret.retn();
7573 }
7574
7575 /*!
7576  * This method makes the assumption that da->getNumberOfTuples()<this->getNumberOfCells(). This method makes the assumption that ids contained in 'da'
7577  * are in [0:getNumberOfCells())
7578  */
7579 DataArrayInt *MEDCouplingUMesh::convertCellArrayPerGeoType(const DataArrayInt *da) const
7580 {
7581   checkFullyDefined();
7582   const int *conn=_nodal_connec->getConstPointer();
7583   const int *connI=_nodal_connec_index->getConstPointer();
7584   int nbOfCells=getNumberOfCells();
7585   std::set<INTERP_KERNEL::NormalizedCellType> types(getAllGeoTypes());
7586   int *tmp=new int[nbOfCells];
7587   for(std::set<INTERP_KERNEL::NormalizedCellType>::const_iterator iter=types.begin();iter!=types.end();iter++)
7588     {
7589       int j=0;
7590       for(const int *i=connI;i!=connI+nbOfCells;i++)
7591         if((INTERP_KERNEL::NormalizedCellType)conn[*i]==(*iter))
7592           tmp[std::distance(connI,i)]=j++;
7593     }
7594   DataArrayInt *ret=DataArrayInt::New();
7595   ret->alloc(da->getNumberOfTuples(),da->getNumberOfComponents());
7596   ret->copyStringInfoFrom(*da);
7597   int *retPtr=ret->getPointer();
7598   const int *daPtr=da->getConstPointer();
7599   int nbOfElems=da->getNbOfElems();
7600   for(int k=0;k<nbOfElems;k++)
7601     retPtr[k]=tmp[daPtr[k]];
7602   delete [] tmp;
7603   return ret;
7604 }
7605
7606 /*!
7607  * This method reduced number of cells of this by keeping cells whose type is different from 'type' and if type=='type'
7608  * This method \b works \b for mesh sorted by type.
7609  * cells whose ids is in 'idsPerGeoType' array.
7610  * This method conserves coords and name of mesh.
7611  */
7612 MEDCouplingUMesh *MEDCouplingUMesh::keepSpecifiedCells(INTERP_KERNEL::NormalizedCellType type, const int *idsPerGeoTypeBg, const int *idsPerGeoTypeEnd) const
7613 {
7614   std::vector<int> code=getDistributionOfTypes();
7615   std::size_t nOfTypesInThis=code.size()/3;
7616   int sz=0,szOfType=0;
7617   for(std::size_t i=0;i<nOfTypesInThis;i++)
7618     {
7619       if(code[3*i]!=type)
7620         sz+=code[3*i+1];
7621       else
7622         szOfType=code[3*i+1];
7623     }
7624   for(const int *work=idsPerGeoTypeBg;work!=idsPerGeoTypeEnd;work++)
7625     if(*work<0 || *work>=szOfType)
7626       {
7627         std::ostringstream oss; oss << "MEDCouplingUMesh::keepSpecifiedCells : Request on type " << type << " at place #" << std::distance(idsPerGeoTypeBg,work) << " value " << *work;
7628         oss << ". It should be in [0," << szOfType << ") !";
7629         throw INTERP_KERNEL::Exception(oss.str().c_str());
7630       }
7631   MCAuto<DataArrayInt> idsTokeep=DataArrayInt::New(); idsTokeep->alloc(sz+(int)std::distance(idsPerGeoTypeBg,idsPerGeoTypeEnd),1);
7632   int *idsPtr=idsTokeep->getPointer();
7633   int offset=0;
7634   for(std::size_t i=0;i<nOfTypesInThis;i++)
7635     {
7636       if(code[3*i]!=type)
7637         for(int j=0;j<code[3*i+1];j++)
7638           *idsPtr++=offset+j;
7639       else
7640         idsPtr=std::transform(idsPerGeoTypeBg,idsPerGeoTypeEnd,idsPtr,std::bind2nd(std::plus<int>(),offset));
7641       offset+=code[3*i+1];
7642     }
7643   MCAuto<MEDCouplingUMesh> ret=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(idsTokeep->begin(),idsTokeep->end(),true));
7644   ret->copyTinyInfoFrom(this);
7645   return ret.retn();
7646 }
7647
7648 /*!
7649  * This method returns a vector of size 'this->getNumberOfCells()'.
7650  * This method retrieves for each cell in \a this if it is linear (false) or quadratic(true).
7651  */
7652 std::vector<bool> MEDCouplingUMesh::getQuadraticStatus() const
7653 {
7654   int ncell=getNumberOfCells();
7655   std::vector<bool> ret(ncell);
7656   const int *cI=getNodalConnectivityIndex()->getConstPointer();
7657   const int *c=getNodalConnectivity()->getConstPointer();
7658   for(int i=0;i<ncell;i++)
7659     {
7660       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)c[cI[i]];
7661       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
7662       ret[i]=cm.isQuadratic();
7663     }
7664   return ret;
7665 }
7666
7667 /*!
7668  * Returns a newly created mesh (with ref count ==1) that contains merge of \a this and \a other.
7669  */
7670 MEDCouplingMesh *MEDCouplingUMesh::mergeMyselfWith(const MEDCouplingMesh *other) const
7671 {
7672   if(other->getType()!=UNSTRUCTURED)
7673     throw INTERP_KERNEL::Exception("Merge of umesh only available with umesh each other !");
7674   const MEDCouplingUMesh *otherC=static_cast<const MEDCouplingUMesh *>(other);
7675   return MergeUMeshes(this,otherC);
7676 }
7677
7678 /*!
7679  * Returns a new DataArrayDouble holding barycenters of all cells. The barycenter is
7680  * computed by averaging coordinates of cell nodes, so this method is not a right
7681  * choice for degnerated meshes (not well oriented, cells with measure close to zero).
7682  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size \a
7683  *          this->getNumberOfCells() tuples per \a this->getSpaceDimension()
7684  *          components. The caller is to delete this array using decrRef() as it is
7685  *          no more needed.
7686  *  \throw If the coordinates array is not set.
7687  *  \throw If the nodal connectivity of cells is not defined.
7688  *  \sa MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell
7689  */
7690 DataArrayDouble *MEDCouplingUMesh::computeCellCenterOfMass() const
7691 {
7692   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7693   int spaceDim=getSpaceDimension();
7694   int nbOfCells=getNumberOfCells();
7695   ret->alloc(nbOfCells,spaceDim);
7696   ret->copyStringInfoFrom(*getCoords());
7697   double *ptToFill=ret->getPointer();
7698   const int *nodal=_nodal_connec->getConstPointer();
7699   const int *nodalI=_nodal_connec_index->getConstPointer();
7700   const double *coor=_coords->getConstPointer();
7701   for(int i=0;i<nbOfCells;i++)
7702     {
7703       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7704       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[i]+1,nodalI[i+1]-nodalI[i]-1,coor,spaceDim,ptToFill);
7705       ptToFill+=spaceDim;
7706     }
7707   return ret.retn();
7708 }
7709
7710 /*!
7711  * This method computes for each cell in \a this, the location of the iso barycenter of nodes constituting
7712  * the cell. Contrary to badly named MEDCouplingUMesh::computeCellCenterOfMass method that returns the center of inertia of the 
7713  * 
7714  * \return a newly allocated DataArrayDouble instance that the caller has to deal with. The returned 
7715  *          DataArrayDouble instance will have \c this->getNumberOfCells() tuples and \c this->getSpaceDimension() components.
7716  * 
7717  * \sa MEDCouplingUMesh::computeCellCenterOfMass
7718  * \throw If \a this is not fully defined (coordinates and connectivity)
7719  * \throw If there is presence in nodal connectivity in \a this of node ids not in [0, \c this->getNumberOfNodes() )
7720  */
7721 DataArrayDouble *MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell() const
7722 {
7723   checkFullyDefined();
7724   MCAuto<DataArrayDouble> ret=DataArrayDouble::New();
7725   int spaceDim=getSpaceDimension();
7726   int nbOfCells=getNumberOfCells();
7727   int nbOfNodes=getNumberOfNodes();
7728   ret->alloc(nbOfCells,spaceDim);
7729   double *ptToFill=ret->getPointer();
7730   const int *nodal=_nodal_connec->getConstPointer();
7731   const int *nodalI=_nodal_connec_index->getConstPointer();
7732   const double *coor=_coords->getConstPointer();
7733   for(int i=0;i<nbOfCells;i++,ptToFill+=spaceDim)
7734     {
7735       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[i]];
7736       std::fill(ptToFill,ptToFill+spaceDim,0.);
7737       if(type!=INTERP_KERNEL::NORM_POLYHED)
7738         {
7739           for(const int *conn=nodal+nodalI[i]+1;conn!=nodal+nodalI[i+1];conn++)
7740             {
7741               if(*conn>=0 && *conn<nbOfNodes)
7742                 std::transform(coor+spaceDim*conn[0],coor+spaceDim*(conn[0]+1),ptToFill,ptToFill,std::plus<double>());
7743               else
7744                 {
7745                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of nodeId #" << *conn << " should be in [0," <<   nbOfNodes << ") !";
7746                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7747                 }
7748             }
7749           int nbOfNodesInCell=nodalI[i+1]-nodalI[i]-1;
7750           if(nbOfNodesInCell>0)
7751             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)nbOfNodesInCell));
7752           else
7753             {
7754               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell #" << i << " presence of cell with no nodes !";
7755               throw INTERP_KERNEL::Exception(oss.str().c_str());
7756             }
7757         }
7758       else
7759         {
7760           std::set<int> s(nodal+nodalI[i]+1,nodal+nodalI[i+1]);
7761           s.erase(-1);
7762           for(std::set<int>::const_iterator it=s.begin();it!=s.end();it++)
7763             {
7764               if(*it>=0 && *it<nbOfNodes)
7765                 std::transform(coor+spaceDim*(*it),coor+spaceDim*((*it)+1),ptToFill,ptToFill,std::plus<double>());
7766               else
7767                 {
7768                   std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on cell polyhedron cell #" << i << " presence of nodeId #" << *it << " should be in [0," <<   nbOfNodes << ") !";
7769                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7770                 }
7771             }
7772           if(!s.empty())
7773             std::transform(ptToFill,ptToFill+spaceDim,ptToFill,std::bind2nd(std::multiplies<double>(),1./(double)s.size()));
7774           else
7775             {
7776               std::ostringstream oss; oss << "MEDCouplingUMesh::computeIsoBarycenterOfNodesPerCell : on polyhedron cell #" << i << " there are no nodes !";
7777               throw INTERP_KERNEL::Exception(oss.str().c_str());
7778             }
7779         }
7780     }
7781   return ret.retn();
7782 }
7783
7784 /*!
7785  * Returns a new DataArrayDouble holding barycenters of specified cells. The
7786  * barycenter is computed by averaging coordinates of cell nodes. The cells to treat
7787  * are specified via an array of cell ids. 
7788  *  \warning Validity of the specified cell ids is not checked! 
7789  *           Valid range is [ 0, \a this->getNumberOfCells() ).
7790  *  \param [in] begin - an array of cell ids of interest.
7791  *  \param [in] end - the end of \a begin, i.e. a pointer to its (last+1)-th element.
7792  *  \return DataArrayDouble * - a new instance of DataArrayDouble, of size ( \a
7793  *          end - \a begin ) tuples per \a this->getSpaceDimension() components. The
7794  *          caller is to delete this array using decrRef() as it is no more needed. 
7795  *  \throw If the coordinates array is not set.
7796  *  \throw If the nodal connectivity of cells is not defined.
7797  *
7798  *  \if ENABLE_EXAMPLES
7799  *  \ref cpp_mcumesh_getPartBarycenterAndOwner "Here is a C++ example".<br>
7800  *  \ref  py_mcumesh_getPartBarycenterAndOwner "Here is a Python example".
7801  *  \endif
7802  */
7803 DataArrayDouble *MEDCouplingUMesh::getPartBarycenterAndOwner(const int *begin, const int *end) const
7804 {
7805   DataArrayDouble *ret=DataArrayDouble::New();
7806   int spaceDim=getSpaceDimension();
7807   int nbOfTuple=(int)std::distance(begin,end);
7808   ret->alloc(nbOfTuple,spaceDim);
7809   double *ptToFill=ret->getPointer();
7810   double *tmp=new double[spaceDim];
7811   const int *nodal=_nodal_connec->getConstPointer();
7812   const int *nodalI=_nodal_connec_index->getConstPointer();
7813   const double *coor=_coords->getConstPointer();
7814   for(const int *w=begin;w!=end;w++)
7815     {
7816       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)nodal[nodalI[*w]];
7817       INTERP_KERNEL::computeBarycenter2<int,INTERP_KERNEL::ALL_C_MODE>(type,nodal+nodalI[*w]+1,nodalI[*w+1]-nodalI[*w]-1,coor,spaceDim,ptToFill);
7818       ptToFill+=spaceDim;
7819     }
7820   delete [] tmp;
7821   return ret;
7822 }
7823
7824 /*!
7825  * 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".
7826  * So the returned instance will have 4 components and \c this->getNumberOfCells() tuples.
7827  * So this method expects that \a this has a spaceDimension equal to 3 and meshDimension equal to 2.
7828  * The computation of the plane equation is done using each time the 3 first nodes of 2D cells.
7829  * This method is useful to detect 2D cells in 3D space that are not coplanar.
7830  * 
7831  * \return DataArrayDouble * - a new instance of DataArrayDouble having 4 components and a number of tuples equal to number of cells in \a this.
7832  * \throw If spaceDim!=3 or meshDim!=2.
7833  * \throw If connectivity of \a this is invalid.
7834  * \throw If connectivity of a cell in \a this points to an invalid node.
7835  */
7836 DataArrayDouble *MEDCouplingUMesh::computePlaneEquationOf3DFaces() const
7837 {
7838   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
7839   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
7840   if(getSpaceDimension()!=3 || getMeshDimension()!=2)
7841     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::computePlaneEquationOf3DFaces : This method must be applied on a mesh having meshDimension equal 2 and a spaceDimension equal to 3 !");
7842   ret->alloc(nbOfCells,4);
7843   double *retPtr(ret->getPointer());
7844   const int *nodal(_nodal_connec->begin()),*nodalI(_nodal_connec_index->begin());
7845   const double *coor(_coords->begin());
7846   for(int i=0;i<nbOfCells;i++,nodalI++,retPtr+=4)
7847     {
7848       double matrix[16]={0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0},matrix2[16];
7849       if(nodalI[1]-nodalI[0]>=3)
7850         {
7851           for(int j=0;j<3;j++)
7852             {
7853               int nodeId(nodal[nodalI[0]+1+j]);
7854               if(nodeId>=0 && nodeId<nbOfNodes)
7855                 std::copy(coor+nodeId*3,coor+(nodeId+1)*3,matrix+4*j);
7856               else
7857                 {
7858                   std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! This cell points to an invalid nodeId : " << nodeId << " !";
7859                   throw INTERP_KERNEL::Exception(oss.str().c_str());
7860                 }
7861             }
7862         }
7863       else
7864         {
7865           std::ostringstream oss; oss << "MEDCouplingUMesh::computePlaneEquationOf3DFaces : invalid 2D cell #" << i << " ! Must be constitued by more than 3 nodes !";
7866           throw INTERP_KERNEL::Exception(oss.str().c_str());
7867         }
7868       INTERP_KERNEL::inverseMatrix(matrix,4,matrix2);
7869       retPtr[0]=matrix2[3]; retPtr[1]=matrix2[7]; retPtr[2]=matrix2[11]; retPtr[3]=matrix2[15];
7870     }
7871   return ret.retn();
7872 }
7873
7874 /*!
7875  * This method expects as input a DataArrayDouble non nul instance 'da' that should be allocated. If not an exception is thrown.
7876  * 
7877  */
7878 MEDCouplingUMesh *MEDCouplingUMesh::Build0DMeshFromCoords(DataArrayDouble *da)
7879 {
7880   if(!da)
7881     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Build0DMeshFromCoords : instance of DataArrayDouble must be not null !");
7882   da->checkAllocated();
7883   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(da->getName(),0);
7884   ret->setCoords(da);
7885   int nbOfTuples=da->getNumberOfTuples();
7886   MCAuto<DataArrayInt> c=DataArrayInt::New();
7887   MCAuto<DataArrayInt> cI=DataArrayInt::New();
7888   c->alloc(2*nbOfTuples,1);
7889   cI->alloc(nbOfTuples+1,1);
7890   int *cp=c->getPointer();
7891   int *cip=cI->getPointer();
7892   *cip++=0;
7893   for(int i=0;i<nbOfTuples;i++)
7894     {
7895       *cp++=INTERP_KERNEL::NORM_POINT1;
7896       *cp++=i;
7897       *cip++=2*(i+1);
7898     }
7899   ret->setConnectivity(c,cI,true);
7900   return ret.retn();
7901 }
7902 /*!
7903  * Creates a new MEDCouplingUMesh by concatenating two given meshes of the same dimension.
7904  * Cells and nodes of
7905  * the first mesh precede cells and nodes of the second mesh within the result mesh.
7906  *  \param [in] mesh1 - the first mesh.
7907  *  \param [in] mesh2 - the second mesh.
7908  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7909  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7910  *          is no more needed.
7911  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
7912  *  \throw If the coordinates array is not set in none of the meshes.
7913  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
7914  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
7915  */
7916 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
7917 {
7918   std::vector<const MEDCouplingUMesh *> tmp(2);
7919   tmp[0]=const_cast<MEDCouplingUMesh *>(mesh1); tmp[1]=const_cast<MEDCouplingUMesh *>(mesh2);
7920   return MergeUMeshes(tmp);
7921 }
7922
7923 /*!
7924  * Creates a new MEDCouplingUMesh by concatenating all given meshes of the same dimension.
7925  * Cells and nodes of
7926  * the *i*-th mesh precede cells and nodes of the (*i*+1)-th mesh within the result mesh.
7927  *  \param [in] a - a vector of meshes (MEDCouplingUMesh) to concatenate.
7928  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
7929  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
7930  *          is no more needed.
7931  *  \throw If \a a.size() == 0.
7932  *  \throw If \a a[ *i* ] == NULL.
7933  *  \throw If the coordinates array is not set in none of the meshes.
7934  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
7935  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
7936  */
7937 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshes(std::vector<const MEDCouplingUMesh *>& a)
7938 {
7939   std::size_t sz=a.size();
7940   if(sz==0)
7941     return MergeUMeshesLL(a);
7942   for(std::size_t ii=0;ii<sz;ii++)
7943     if(!a[ii])
7944       {
7945         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshes : item #" << ii << " in input array of size "<< sz << " is empty !";
7946         throw INTERP_KERNEL::Exception(oss.str().c_str());
7947       }
7948   std::vector< MCAuto<MEDCouplingUMesh> > bb(sz);
7949   std::vector< const MEDCouplingUMesh * > aa(sz);
7950   int spaceDim=-3;
7951   for(std::size_t i=0;i<sz && spaceDim==-3;i++)
7952     {
7953       const MEDCouplingUMesh *cur=a[i];
7954       const DataArrayDouble *coo=cur->getCoords();
7955       if(coo)
7956         spaceDim=coo->getNumberOfComponents();
7957     }
7958   if(spaceDim==-3)
7959     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : no spaceDim specified ! unable to perform merge !");
7960   for(std::size_t i=0;i<sz;i++)
7961     {
7962       bb[i]=a[i]->buildSetInstanceFromThis(spaceDim);
7963       aa[i]=bb[i];
7964     }
7965   return MergeUMeshesLL(aa);
7966 }
7967
7968 /// @cond INTERNAL
7969
7970 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesLL(std::vector<const MEDCouplingUMesh *>& a)
7971 {
7972   if(a.empty())
7973     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::MergeUMeshes : input array must be NON EMPTY !");
7974   std::vector<const MEDCouplingUMesh *>::const_iterator it=a.begin();
7975   int meshDim=(*it)->getMeshDimension();
7976   int nbOfCells=(*it)->getNumberOfCells();
7977   int meshLgth=(*it++)->getNodalConnectivityArrayLen();
7978   for(;it!=a.end();it++)
7979     {
7980       if(meshDim!=(*it)->getMeshDimension())
7981         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, MergeUMeshes impossible !");
7982       nbOfCells+=(*it)->getNumberOfCells();
7983       meshLgth+=(*it)->getNodalConnectivityArrayLen();
7984     }
7985   std::vector<const MEDCouplingPointSet *> aps(a.size());
7986   std::copy(a.begin(),a.end(),aps.begin());
7987   MCAuto<DataArrayDouble> pts=MergeNodesArray(aps);
7988   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New("merge",meshDim);
7989   ret->setCoords(pts);
7990   MCAuto<DataArrayInt> c=DataArrayInt::New();
7991   c->alloc(meshLgth,1);
7992   int *cPtr=c->getPointer();
7993   MCAuto<DataArrayInt> cI=DataArrayInt::New();
7994   cI->alloc(nbOfCells+1,1);
7995   int *cIPtr=cI->getPointer();
7996   *cIPtr++=0;
7997   int offset=0;
7998   int offset2=0;
7999   for(it=a.begin();it!=a.end();it++)
8000     {
8001       int curNbOfCell=(*it)->getNumberOfCells();
8002       const int *curCI=(*it)->_nodal_connec_index->getConstPointer();
8003       const int *curC=(*it)->_nodal_connec->getConstPointer();
8004       cIPtr=std::transform(curCI+1,curCI+curNbOfCell+1,cIPtr,std::bind2nd(std::plus<int>(),offset));
8005       for(int j=0;j<curNbOfCell;j++)
8006         {
8007           const int *src=curC+curCI[j];
8008           *cPtr++=*src++;
8009           for(;src!=curC+curCI[j+1];src++,cPtr++)
8010             {
8011               if(*src!=-1)
8012                 *cPtr=*src+offset2;
8013               else
8014                 *cPtr=-1;
8015             }
8016         }
8017       offset+=curCI[curNbOfCell];
8018       offset2+=(*it)->getNumberOfNodes();
8019     }
8020   //
8021   ret->setConnectivity(c,cI,true);
8022   return ret.retn();
8023 }
8024
8025 /// @endcond
8026
8027 /*!
8028  * Creates a new MEDCouplingUMesh by concatenating cells of two given meshes of same
8029  * dimension and sharing the node coordinates array.
8030  * All cells of the first mesh precede all cells of the second mesh
8031  * within the result mesh. 
8032  *  \param [in] mesh1 - the first mesh.
8033  *  \param [in] mesh2 - the second mesh.
8034  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8035  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8036  *          is no more needed.
8037  *  \throw If \a mesh1 == NULL or \a mesh2 == NULL.
8038  *  \throw If the meshes do not share the node coordinates array.
8039  *  \throw If \a mesh1->getMeshDimension() < 0 or \a mesh2->getMeshDimension() < 0.
8040  *  \throw If \a mesh1->getMeshDimension() != \a mesh2->getMeshDimension().
8041  */
8042 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const MEDCouplingUMesh *mesh1, const MEDCouplingUMesh *mesh2)
8043 {
8044   std::vector<const MEDCouplingUMesh *> tmp(2);
8045   tmp[0]=mesh1; tmp[1]=mesh2;
8046   return MergeUMeshesOnSameCoords(tmp);
8047 }
8048
8049 /*!
8050  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8051  * dimension and sharing the node coordinates array.
8052  * All cells of the *i*-th mesh precede all cells of the
8053  * (*i*+1)-th mesh within the result mesh.
8054  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8055  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8056  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8057  *          is no more needed.
8058  *  \throw If \a a.size() == 0.
8059  *  \throw If \a a[ *i* ] == NULL.
8060  *  \throw If the meshes do not share the node coordinates array.
8061  *  \throw If \a a[ *i* ]->getMeshDimension() < 0.
8062  *  \throw If the meshes in \a a are of different dimension (getMeshDimension()).
8063  */
8064 MEDCouplingUMesh *MEDCouplingUMesh::MergeUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes)
8065 {
8066   if(meshes.empty())
8067     throw INTERP_KERNEL::Exception("meshes input parameter is expected to be non empty.");
8068   for(std::size_t ii=0;ii<meshes.size();ii++)
8069     if(!meshes[ii])
8070       {
8071         std::ostringstream oss; oss << "MEDCouplingUMesh::MergeUMeshesOnSameCoords : item #" << ii << " in input array of size "<< meshes.size() << " is empty !";
8072         throw INTERP_KERNEL::Exception(oss.str().c_str());
8073       }
8074   const DataArrayDouble *coords=meshes.front()->getCoords();
8075   int meshDim=meshes.front()->getMeshDimension();
8076   std::vector<const MEDCouplingUMesh *>::const_iterator iter=meshes.begin();
8077   int meshLgth=0;
8078   int meshIndexLgth=0;
8079   for(;iter!=meshes.end();iter++)
8080     {
8081       if(coords!=(*iter)->getCoords())
8082         throw INTERP_KERNEL::Exception("meshes does not share the same coords ! Try using tryToShareSameCoords method !");
8083       if(meshDim!=(*iter)->getMeshDimension())
8084         throw INTERP_KERNEL::Exception("Mesh dimensions mismatches, FuseUMeshesOnSameCoords impossible !");
8085       meshLgth+=(*iter)->getNodalConnectivityArrayLen();
8086       meshIndexLgth+=(*iter)->getNumberOfCells();
8087     }
8088   MCAuto<DataArrayInt> nodal=DataArrayInt::New();
8089   nodal->alloc(meshLgth,1);
8090   int *nodalPtr=nodal->getPointer();
8091   MCAuto<DataArrayInt> nodalIndex=DataArrayInt::New();
8092   nodalIndex->alloc(meshIndexLgth+1,1);
8093   int *nodalIndexPtr=nodalIndex->getPointer();
8094   int offset=0;
8095   for(iter=meshes.begin();iter!=meshes.end();iter++)
8096     {
8097       const int *nod=(*iter)->getNodalConnectivity()->getConstPointer();
8098       const int *index=(*iter)->getNodalConnectivityIndex()->getConstPointer();
8099       int nbOfCells=(*iter)->getNumberOfCells();
8100       int meshLgth2=(*iter)->getNodalConnectivityArrayLen();
8101       nodalPtr=std::copy(nod,nod+meshLgth2,nodalPtr);
8102       if(iter!=meshes.begin())
8103         nodalIndexPtr=std::transform(index+1,index+nbOfCells+1,nodalIndexPtr,std::bind2nd(std::plus<int>(),offset));
8104       else
8105         nodalIndexPtr=std::copy(index,index+nbOfCells+1,nodalIndexPtr);
8106       offset+=meshLgth2;
8107     }
8108   MEDCouplingUMesh *ret=MEDCouplingUMesh::New();
8109   ret->setName("merge");
8110   ret->setMeshDimension(meshDim);
8111   ret->setConnectivity(nodal,nodalIndex,true);
8112   ret->setCoords(coords);
8113   return ret;
8114 }
8115
8116 /*!
8117  * Creates a new MEDCouplingUMesh by concatenating cells of all given meshes of same
8118  * dimension and sharing the node coordinates array. Cells of the *i*-th mesh precede
8119  * cells of the (*i*+1)-th mesh within the result mesh. Duplicates of cells are
8120  * removed from \a this mesh and arrays mapping between new and old cell ids in "Old to
8121  * New" mode are returned for each input mesh.
8122  *  \param [in] meshes - a vector of meshes (MEDCouplingUMesh) to concatenate.
8123  *  \param [in] compType - specifies a cell comparison technique. For meaning of its
8124  *          valid values [0,1,2], see zipConnectivityTraducer().
8125  *  \param [in,out] corr - an array of DataArrayInt, of the same size as \a
8126  *          meshes. The *i*-th array describes cell ids mapping for \a meshes[ *i* ]
8127  *          mesh. The caller is to delete each of the arrays using decrRef() as it is
8128  *          no more needed.
8129  *  \return MEDCouplingUMesh * - the result mesh. It is a new instance of
8130  *          MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
8131  *          is no more needed.
8132  *  \throw If \a meshes.size() == 0.
8133  *  \throw If \a meshes[ *i* ] == NULL.
8134  *  \throw If the meshes do not share the node coordinates array.
8135  *  \throw If \a meshes[ *i* ]->getMeshDimension() < 0.
8136  *  \throw If the \a meshes are of different dimension (getMeshDimension()).
8137  *  \throw If the nodal connectivity of cells of any of \a meshes is not defined.
8138  *  \throw If the nodal connectivity any of \a meshes includes an invalid id.
8139  */
8140 MEDCouplingUMesh *MEDCouplingUMesh::FuseUMeshesOnSameCoords(const std::vector<const MEDCouplingUMesh *>& meshes, int compType, std::vector<DataArrayInt *>& corr)
8141 {
8142   //All checks are delegated to MergeUMeshesOnSameCoords
8143   MCAuto<MEDCouplingUMesh> ret=MergeUMeshesOnSameCoords(meshes);
8144   MCAuto<DataArrayInt> o2n=ret->zipConnectivityTraducer(compType);
8145   corr.resize(meshes.size());
8146   std::size_t nbOfMeshes=meshes.size();
8147   int offset=0;
8148   const int *o2nPtr=o2n->getConstPointer();
8149   for(std::size_t i=0;i<nbOfMeshes;i++)
8150     {
8151       DataArrayInt *tmp=DataArrayInt::New();
8152       int curNbOfCells=meshes[i]->getNumberOfCells();
8153       tmp->alloc(curNbOfCells,1);
8154       std::copy(o2nPtr+offset,o2nPtr+offset+curNbOfCells,tmp->getPointer());
8155       offset+=curNbOfCells;
8156       tmp->setName(meshes[i]->getName());
8157       corr[i]=tmp;
8158     }
8159   return ret.retn();
8160 }
8161
8162 /*!
8163  * Makes all given meshes share the nodal connectivity array. The common connectivity
8164  * array is created by concatenating the connectivity arrays of all given meshes. All
8165  * the given meshes must be of the same space dimension but dimension of cells **can
8166  * differ**. This method is particulary useful in MEDLoader context to build a \ref
8167  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8168  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array.
8169  *  \param [in,out] meshes - a vector of meshes to update.
8170  *  \throw If any of \a meshes is NULL.
8171  *  \throw If the coordinates array is not set in any of \a meshes.
8172  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8173  *  \throw If \a meshes are of different space dimension.
8174  */
8175 void MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords(const std::vector<MEDCouplingUMesh *>& meshes)
8176 {
8177   std::size_t sz=meshes.size();
8178   if(sz==0 || sz==1)
8179     return;
8180   std::vector< const DataArrayDouble * > coords(meshes.size());
8181   std::vector< const DataArrayDouble * >::iterator it2=coords.begin();
8182   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,it2++)
8183     {
8184       if((*it))
8185         {
8186           (*it)->checkConnectivityFullyDefined();
8187           const DataArrayDouble *coo=(*it)->getCoords();
8188           if(coo)
8189             *it2=coo;
8190           else
8191             {
8192               std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8193               oss << " has no coordinate array defined !";
8194               throw INTERP_KERNEL::Exception(oss.str().c_str());
8195             }
8196         }
8197       else
8198         {
8199           std::ostringstream oss; oss << " MEDCouplingUMesh::PutUMeshesOnSameAggregatedCoords : Item #" << std::distance(meshes.begin(),it) << " inside the vector of length " << meshes.size();
8200           oss << " is null !";
8201           throw INTERP_KERNEL::Exception(oss.str().c_str());
8202         }
8203     }
8204   MCAuto<DataArrayDouble> res=DataArrayDouble::Aggregate(coords);
8205   std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();
8206   int offset=(*it)->getNumberOfNodes();
8207   (*it++)->setCoords(res);
8208   for(;it!=meshes.end();it++)
8209     {
8210       int oldNumberOfNodes=(*it)->getNumberOfNodes();
8211       (*it)->setCoords(res);
8212       (*it)->shiftNodeNumbersInConn(offset);
8213       offset+=oldNumberOfNodes;
8214     }
8215 }
8216
8217 /*!
8218  * Merges nodes coincident with a given precision within all given meshes that share
8219  * the nodal connectivity array. The given meshes **can be of different** mesh
8220  * dimension. This method is particulary useful in MEDLoader context to build a \ref
8221  * MEDCoupling::MEDFileUMesh "MEDFileUMesh" instance that expects that underlying
8222  * MEDCouplingUMesh'es of different dimension share the same nodal connectivity array. 
8223  *  \param [in,out] meshes - a vector of meshes to update.
8224  *  \param [in] eps - the precision used to detect coincident nodes (infinite norm).
8225  *  \throw If any of \a meshes is NULL.
8226  *  \throw If the \a meshes do not share the same node coordinates array.
8227  *  \throw If the nodal connectivity of cells is not defined in any of \a meshes.
8228  */
8229 void MEDCouplingUMesh::MergeNodesOnUMeshesSharingSameCoords(const std::vector<MEDCouplingUMesh *>& meshes, double eps)
8230 {
8231   if(meshes.empty())
8232     return ;
8233   std::set<const DataArrayDouble *> s;
8234   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8235     {
8236       if(*it)
8237         s.insert((*it)->getCoords());
8238       else
8239         {
8240           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 !";
8241           throw INTERP_KERNEL::Exception(oss.str().c_str());
8242         }
8243     }
8244   if(s.size()!=1)
8245     {
8246       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 !";
8247       throw INTERP_KERNEL::Exception(oss.str().c_str());
8248     }
8249   const DataArrayDouble *coo=*(s.begin());
8250   if(!coo)
8251     return;
8252   //
8253   DataArrayInt *comm,*commI;
8254   coo->findCommonTuples(eps,-1,comm,commI);
8255   MCAuto<DataArrayInt> tmp1(comm),tmp2(commI);
8256   int oldNbOfNodes=coo->getNumberOfTuples();
8257   int newNbOfNodes;
8258   MCAuto<DataArrayInt> o2n=DataArrayInt::ConvertIndexArrayToO2N(oldNbOfNodes,comm->begin(),commI->begin(),commI->end(),newNbOfNodes);
8259   if(oldNbOfNodes==newNbOfNodes)
8260     return ;
8261   MCAuto<DataArrayDouble> newCoords=coo->renumberAndReduce(o2n->getConstPointer(),newNbOfNodes);
8262   for(std::vector<MEDCouplingUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++)
8263     {
8264       (*it)->renumberNodesInConn(o2n->getConstPointer());
8265       (*it)->setCoords(newCoords);
8266     } 
8267 }
8268
8269 /*!
8270  * 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.
8271  * \param nbOfNodesPerLev in parameter that specifies the number of nodes of one slice of global dataset
8272  * \param isQuad specifies the policy of connectivity.
8273  * @ret in/out parameter in which the result will be append
8274  */
8275 void MEDCouplingUMesh::AppendExtrudedCell(const int *connBg, const int *connEnd, int nbOfNodesPerLev, bool isQuad, std::vector<int>& ret)
8276 {
8277   INTERP_KERNEL::NormalizedCellType flatType=(INTERP_KERNEL::NormalizedCellType)connBg[0];
8278   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(flatType);
8279   ret.push_back(cm.getExtrudedType());
8280   int deltaz=isQuad?2*nbOfNodesPerLev:nbOfNodesPerLev;
8281   switch(flatType)
8282   {
8283     case INTERP_KERNEL::NORM_POINT1:
8284       {
8285         ret.push_back(connBg[1]);
8286         ret.push_back(connBg[1]+nbOfNodesPerLev);
8287         break;
8288       }
8289     case INTERP_KERNEL::NORM_SEG2:
8290       {
8291         int conn[4]={connBg[1],connBg[2],connBg[2]+deltaz,connBg[1]+deltaz};
8292         ret.insert(ret.end(),conn,conn+4);
8293         break;
8294       }
8295     case INTERP_KERNEL::NORM_SEG3:
8296       {
8297         int conn[8]={connBg[1],connBg[3],connBg[3]+deltaz,connBg[1]+deltaz,connBg[2],connBg[3]+nbOfNodesPerLev,connBg[2]+deltaz,connBg[1]+nbOfNodesPerLev};
8298         ret.insert(ret.end(),conn,conn+8);
8299         break;
8300       }
8301     case INTERP_KERNEL::NORM_QUAD4:
8302       {
8303         int conn[8]={connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz};
8304         ret.insert(ret.end(),conn,conn+8);
8305         break;
8306       }
8307     case INTERP_KERNEL::NORM_TRI3:
8308       {
8309         int conn[6]={connBg[1],connBg[2],connBg[3],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz};
8310         ret.insert(ret.end(),conn,conn+6);
8311         break;
8312       }
8313     case INTERP_KERNEL::NORM_TRI6:
8314       {
8315         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,
8316           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev};
8317         ret.insert(ret.end(),conn,conn+15);
8318         break;
8319       }
8320     case INTERP_KERNEL::NORM_QUAD8:
8321       {
8322         int conn[20]={
8323           connBg[1],connBg[2],connBg[3],connBg[4],connBg[1]+deltaz,connBg[2]+deltaz,connBg[3]+deltaz,connBg[4]+deltaz,
8324           connBg[5],connBg[6],connBg[7],connBg[8],connBg[5]+deltaz,connBg[6]+deltaz,connBg[7]+deltaz,connBg[8]+deltaz,
8325           connBg[1]+nbOfNodesPerLev,connBg[2]+nbOfNodesPerLev,connBg[3]+nbOfNodesPerLev,connBg[4]+nbOfNodesPerLev
8326         };
8327         ret.insert(ret.end(),conn,conn+20);
8328         break;
8329       }
8330     case INTERP_KERNEL::NORM_POLYGON:
8331       {
8332         std::back_insert_iterator< std::vector<int> > ii(ret);
8333         std::copy(connBg+1,connEnd,ii);
8334         *ii++=-1;
8335         std::reverse_iterator<const int *> rConnBg(connEnd);
8336         std::reverse_iterator<const int *> rConnEnd(connBg+1);
8337         std::transform(rConnBg,rConnEnd,ii,std::bind2nd(std::plus<int>(),deltaz));
8338         std::size_t nbOfRadFaces=std::distance(connBg+1,connEnd);
8339         for(std::size_t i=0;i<nbOfRadFaces;i++)
8340           {
8341             *ii++=-1;
8342             int conn[4]={connBg[(i+1)%nbOfRadFaces+1],connBg[i+1],connBg[i+1]+deltaz,connBg[(i+1)%nbOfRadFaces+1]+deltaz};
8343             std::copy(conn,conn+4,ii);
8344           }
8345         break;
8346       }
8347     default:
8348       throw INTERP_KERNEL::Exception("A flat type has been detected that has not its extruded representation !");
8349   }
8350 }
8351
8352 /*!
8353  * This static operates only for coords in 3D. The polygon is specfied by its connectivity nodes in [ \a begin , \a end ).
8354  */
8355 bool MEDCouplingUMesh::IsPolygonWellOriented(bool isQuadratic, const double *vec, const int *begin, const int *end, const double *coords)
8356 {
8357   std::size_t i, ip1;
8358   double v[3]={0.,0.,0.};
8359   std::size_t sz=std::distance(begin,end);
8360   if(isQuadratic)
8361     sz/=2;
8362   for(i=0;i<sz;i++)
8363     {
8364       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];
8365       v[1]+=coords[3*begin[i]+2]*coords[3*begin[(i+1)%sz]]-coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+2];
8366       v[2]+=coords[3*begin[i]]*coords[3*begin[(i+1)%sz]+1]-coords[3*begin[i]+1]*coords[3*begin[(i+1)%sz]];
8367     }
8368   double ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8369
8370   // Try using quadratic points if standard points are degenerated (for example a QPOLYG with two
8371   // SEG3 forming a circle):
8372   if (fabs(ret) < INTERP_KERNEL::DEFAULT_ABS_TOL && isQuadratic)
8373     {
8374       v[0] = 0.0; v[1] = 0.0; v[2] = 0.0;
8375       for(std::size_t j=0;j<sz;j++)
8376         {
8377           if (j%2)  // current point i is quadratic, next point i+1 is standard
8378             {
8379               i = sz+j;
8380               ip1 = (j+1)%sz; // ip1 = "i+1"
8381             }
8382           else      // current point i is standard, next point i+1 is quadratic
8383             {
8384               i = j;
8385               ip1 = j+sz;
8386             }
8387           v[0]+=coords[3*begin[i]+1]*coords[3*begin[ip1]+2]-coords[3*begin[i]+2]*coords[3*begin[ip1]+1];
8388           v[1]+=coords[3*begin[i]+2]*coords[3*begin[ip1]]-coords[3*begin[i]]*coords[3*begin[ip1]+2];
8389           v[2]+=coords[3*begin[i]]*coords[3*begin[ip1]+1]-coords[3*begin[i]+1]*coords[3*begin[ip1]];
8390         }
8391       ret = vec[0]*v[0]+vec[1]*v[1]+vec[2]*v[2];
8392     }
8393   return (ret>0.);
8394 }
8395
8396 /*!
8397  * The polyhedron is specfied by its connectivity nodes in [ \a begin , \a end ).
8398  */
8399 bool MEDCouplingUMesh::IsPolyhedronWellOriented(const int *begin, const int *end, const double *coords)
8400 {
8401   std::vector<std::pair<int,int> > edges;
8402   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8403   const int *bgFace=begin;
8404   for(std::size_t i=0;i<nbOfFaces;i++)
8405     {
8406       const int *endFace=std::find(bgFace+1,end,-1);
8407       std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8408       for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8409         {
8410           std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8411           if(std::find(edges.begin(),edges.end(),p1)!=edges.end())
8412             return false;
8413           edges.push_back(p1);
8414         }
8415       bgFace=endFace+1;
8416     }
8417   return INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)>-EPS_FOR_POLYH_ORIENTATION;
8418 }
8419
8420 /*!
8421  * The 3D extruded static cell (PENTA6,HEXA8,HEXAGP12...) its connectivity nodes in [ \a begin , \a end ).
8422  */
8423 bool MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented(const int *begin, const int *end, const double *coords)
8424 {
8425   double vec0[3],vec1[3];
8426   std::size_t sz=std::distance(begin,end);
8427   if(sz%2!=0)
8428     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Is3DExtrudedStaticCellWellOriented : the length of nodal connectivity of extruded cell is not even !");
8429   int nbOfNodes=(int)sz/2;
8430   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,nbOfNodes,coords,vec0);
8431   const double *pt0=coords+3*begin[0];
8432   const double *pt1=coords+3*begin[nbOfNodes];
8433   vec1[0]=pt1[0]-pt0[0]; vec1[1]=pt1[1]-pt0[1]; vec1[2]=pt1[2]-pt0[2];
8434   return (vec0[0]*vec1[0]+vec0[1]*vec1[1]+vec0[2]*vec1[2])<0.;
8435 }
8436
8437 void MEDCouplingUMesh::CorrectExtrudedStaticCell(int *begin, int *end)
8438 {
8439   std::size_t sz=std::distance(begin,end);
8440   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
8441   std::size_t nbOfNodes(sz/2);
8442   std::copy(begin,end,(int *)tmp);
8443   for(std::size_t j=1;j<nbOfNodes;j++)
8444     {
8445       begin[j]=tmp[nbOfNodes-j];
8446       begin[j+nbOfNodes]=tmp[nbOfNodes+nbOfNodes-j];
8447     }
8448 }
8449
8450 bool MEDCouplingUMesh::IsTetra4WellOriented(const int *begin, const int *end, const double *coords)
8451 {
8452   std::size_t sz=std::distance(begin,end);
8453   if(sz!=4)
8454     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsTetra4WellOriented : Tetra4 cell with not 4 nodes ! Call checkConsistency !");
8455   double vec0[3],vec1[3];
8456   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[1],*pt2=coords+3*begin[2],*pt3=coords+3*begin[3];
8457   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]; 
8458   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;
8459 }
8460
8461 bool MEDCouplingUMesh::IsPyra5WellOriented(const int *begin, const int *end, const double *coords)
8462 {
8463   std::size_t sz=std::distance(begin,end);
8464   if(sz!=5)
8465     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::IsPyra5WellOriented : Pyra5 cell with not 5 nodes ! Call checkConsistency !");
8466   double vec0[3];
8467   INTERP_KERNEL::areaVectorOfPolygon<int,INTERP_KERNEL::ALL_C_MODE>(begin,4,coords,vec0);
8468   const double *pt0=coords+3*begin[0],*pt1=coords+3*begin[4];
8469   return (vec0[0]*(pt1[0]-pt0[0])+vec0[1]*(pt1[1]-pt0[1])+vec0[2]*(pt1[2]-pt0[2]))<0.;
8470 }
8471
8472 /*!
8473  * 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 ) 
8474  * 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
8475  * a 2D space.
8476  *
8477  * \param [in] eps is a relative precision that allows to establish if some 3D plane are coplanar or not.
8478  * \param [in] coords the coordinates with nb of components exactly equal to 3
8479  * \param [in] begin begin of the nodal connectivity (geometric type included) of a single polyhedron cell
8480  * \param [in] end end of nodal connectivity of a single polyhedron cell (excluded)
8481  * \param [out] res the result is put at the end of the vector without any alteration of the data.
8482  */
8483 void MEDCouplingUMesh::SimplifyPolyhedronCell(double eps, const DataArrayDouble *coords, const int *begin, const int *end, DataArrayInt *res)
8484 {
8485   int nbFaces=std::count(begin+1,end,-1)+1;
8486   MCAuto<DataArrayDouble> v=DataArrayDouble::New(); v->alloc(nbFaces,3);
8487   double *vPtr=v->getPointer();
8488   MCAuto<DataArrayDouble> p=DataArrayDouble::New(); p->alloc(nbFaces,1);
8489   double *pPtr=p->getPointer();
8490   const int *stFaceConn=begin+1;
8491   for(int i=0;i<nbFaces;i++,vPtr+=3,pPtr++)
8492     {
8493       const int *endFaceConn=std::find(stFaceConn,end,-1);
8494       ComputeVecAndPtOfFace(eps,coords->getConstPointer(),stFaceConn,endFaceConn,vPtr,pPtr);
8495       stFaceConn=endFaceConn+1;
8496     }
8497   pPtr=p->getPointer(); vPtr=v->getPointer();
8498   DataArrayInt *comm1=0,*commI1=0;
8499   v->findCommonTuples(eps,-1,comm1,commI1);
8500   MCAuto<DataArrayInt> comm1Auto(comm1),commI1Auto(commI1);
8501   const int *comm1Ptr=comm1->getConstPointer();
8502   const int *commI1Ptr=commI1->getConstPointer();
8503   int nbOfGrps1=commI1Auto->getNumberOfTuples()-1;
8504   res->pushBackSilent((int)INTERP_KERNEL::NORM_POLYHED);
8505   //
8506   MCAuto<MEDCouplingUMesh> mm=MEDCouplingUMesh::New("",3);
8507   mm->setCoords(const_cast<DataArrayDouble *>(coords)); mm->allocateCells(1); mm->insertNextCell(INTERP_KERNEL::NORM_POLYHED,(int)std::distance(begin+1,end),begin+1);
8508   mm->finishInsertingCells();
8509   //
8510   for(int i=0;i<nbOfGrps1;i++)
8511     {
8512       int vecId=comm1Ptr[commI1Ptr[i]];
8513       MCAuto<DataArrayDouble> tmpgrp2=p->selectByTupleId(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8514       DataArrayInt *comm2=0,*commI2=0;
8515       tmpgrp2->findCommonTuples(eps,-1,comm2,commI2);
8516       MCAuto<DataArrayInt> comm2Auto(comm2),commI2Auto(commI2);
8517       const int *comm2Ptr=comm2->getConstPointer();
8518       const int *commI2Ptr=commI2->getConstPointer();
8519       int nbOfGrps2=commI2Auto->getNumberOfTuples()-1;
8520       for(int j=0;j<nbOfGrps2;j++)
8521         {
8522           if(commI2Ptr[j+1]-commI2Ptr[j]<=1)
8523             {
8524               res->insertAtTheEnd(begin,end);
8525               res->pushBackSilent(-1);
8526             }
8527           else
8528             {
8529               int pointId=comm1Ptr[commI1Ptr[i]+comm2Ptr[commI2Ptr[j]]];
8530               MCAuto<DataArrayInt> ids2=comm2->selectByTupleIdSafeSlice(commI2Ptr[j],commI2Ptr[j+1],1);
8531               ids2->transformWithIndArr(comm1Ptr+commI1Ptr[i],comm1Ptr+commI1Ptr[i+1]);
8532               DataArrayInt *tmp0=DataArrayInt::New(),*tmp1=DataArrayInt::New(),*tmp2=DataArrayInt::New(),*tmp3=DataArrayInt::New();
8533               MCAuto<MEDCouplingUMesh> mm2=mm->buildDescendingConnectivity(tmp0,tmp1,tmp2,tmp3); tmp0->decrRef(); tmp1->decrRef(); tmp2->decrRef(); tmp3->decrRef();
8534               MCAuto<MEDCouplingUMesh> mm3=static_cast<MEDCouplingUMesh *>(mm2->buildPartOfMySelf(ids2->begin(),ids2->end(),true));
8535               MCAuto<DataArrayInt> idsNodeTmp=mm3->zipCoordsTraducer();
8536               MCAuto<DataArrayInt> idsNode=idsNodeTmp->invertArrayO2N2N2O(mm3->getNumberOfNodes());
8537               const int *idsNodePtr=idsNode->getConstPointer();
8538               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];
8539               double vec[3]; vec[0]=vPtr[3*vecId+1]; vec[1]=-vPtr[3*vecId]; vec[2]=0.;
8540               double norm=vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
8541               if(std::abs(norm)>eps)
8542                 {
8543                   double angle=INTERP_KERNEL::EdgeArcCircle::SafeAsin(norm);
8544                   mm3->rotate(center,vec,angle);
8545                 }
8546               mm3->changeSpaceDimension(2);
8547               MCAuto<MEDCouplingUMesh> mm4=mm3->buildSpreadZonesWithPoly();
8548               const int *conn4=mm4->getNodalConnectivity()->getConstPointer();
8549               const int *connI4=mm4->getNodalConnectivityIndex()->getConstPointer();
8550               int nbOfCells=mm4->getNumberOfCells();
8551               for(int k=0;k<nbOfCells;k++)
8552                 {
8553                   int l=0;
8554                   for(const int *work=conn4+connI4[k]+1;work!=conn4+connI4[k+1];work++,l++)
8555                     res->pushBackSilent(idsNodePtr[*work]);
8556                   res->pushBackSilent(-1);
8557                 }
8558             }
8559         }
8560     }
8561   res->popBackSilent();
8562 }
8563
8564 /*!
8565  * 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
8566  * through origin. The plane is defined by its nodal connectivity [ \b begin, \b end ).
8567  * 
8568  * \param [in] eps below that value the dot product of 2 vectors is considered as colinears
8569  * \param [in] coords coordinates expected to have 3 components.
8570  * \param [in] begin start of the nodal connectivity of the face.
8571  * \param [in] end end of the nodal connectivity (excluded) of the face.
8572  * \param [out] v the normalized vector of size 3
8573  * \param [out] p the pos of plane
8574  */
8575 void MEDCouplingUMesh::ComputeVecAndPtOfFace(double eps, const double *coords, const int *begin, const int *end, double *v, double *p)
8576 {
8577   std::size_t nbPoints=std::distance(begin,end);
8578   if(nbPoints<3)
8579     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeVecAndPtOfFace : < of 3 points in face ! not able to find a plane on that face !");
8580   double vec[3]={0.,0.,0.};
8581   std::size_t j=0;
8582   bool refFound=false;
8583   for(;j<nbPoints-1 && !refFound;j++)
8584     {
8585       vec[0]=coords[3*begin[j+1]]-coords[3*begin[j]];
8586       vec[1]=coords[3*begin[j+1]+1]-coords[3*begin[j]+1];
8587       vec[2]=coords[3*begin[j+1]+2]-coords[3*begin[j]+2];
8588       double norm=sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
8589       if(norm>eps)
8590         {
8591           refFound=true;
8592           vec[0]/=norm; vec[1]/=norm; vec[2]/=norm;
8593         }
8594     }
8595   for(std::size_t i=j;i<nbPoints-1;i++)
8596     {
8597       double curVec[3];
8598       curVec[0]=coords[3*begin[i+1]]-coords[3*begin[i]];
8599       curVec[1]=coords[3*begin[i+1]+1]-coords[3*begin[i]+1];
8600       curVec[2]=coords[3*begin[i+1]+2]-coords[3*begin[i]+2];
8601       double norm=sqrt(curVec[0]*curVec[0]+curVec[1]*curVec[1]+curVec[2]*curVec[2]);
8602       if(norm<eps)
8603         continue;
8604       curVec[0]/=norm; curVec[1]/=norm; curVec[2]/=norm;
8605       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];
8606       norm=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
8607       if(norm>eps)
8608         {
8609           v[0]/=norm; v[1]/=norm; v[2]/=norm;
8610           *p=v[0]*coords[3*begin[i]]+v[1]*coords[3*begin[i]+1]+v[2]*coords[3*begin[i]+2];
8611           return ;
8612         }
8613     }
8614   throw INTERP_KERNEL::Exception("Not able to find a normal vector of that 3D face !");
8615 }
8616
8617 /*!
8618  * This method tries to obtain a well oriented polyhedron.
8619  * If the algorithm fails, an exception will be thrown.
8620  */
8621 void MEDCouplingUMesh::TryToCorrectPolyhedronOrientation(int *begin, int *end, const double *coords)
8622 {
8623   std::list< std::pair<int,int> > edgesOK,edgesFinished;
8624   std::size_t nbOfFaces=std::count(begin,end,-1)+1;
8625   std::vector<bool> isPerm(nbOfFaces,false);//field on faces False: I don't know, True : oriented
8626   isPerm[0]=true;
8627   int *bgFace=begin,*endFace=std::find(begin+1,end,-1);
8628   std::size_t nbOfEdgesInFace=std::distance(bgFace,endFace);
8629   for(std::size_t l=0;l<nbOfEdgesInFace;l++) { std::pair<int,int> p1(bgFace[l],bgFace[(l+1)%nbOfEdgesInFace]); edgesOK.push_back(p1); }
8630   //
8631   while(std::find(isPerm.begin(),isPerm.end(),false)!=isPerm.end())
8632     {
8633       bgFace=begin;
8634       std::size_t smthChanged=0;
8635       for(std::size_t i=0;i<nbOfFaces;i++)
8636         {
8637           endFace=std::find(bgFace+1,end,-1);
8638           nbOfEdgesInFace=std::distance(bgFace,endFace);
8639           if(!isPerm[i])
8640             {
8641               bool b;
8642               for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8643                 {
8644                   std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8645                   std::pair<int,int> p2(p1.second,p1.first);
8646                   bool b1=std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end();
8647                   bool b2=std::find(edgesOK.begin(),edgesOK.end(),p2)!=edgesOK.end();
8648                   if(b1 || b2) { b=b2; isPerm[i]=true; smthChanged++; break; }
8649                 }
8650               if(isPerm[i])
8651                 { 
8652                   if(!b)
8653                     std::reverse(bgFace+1,endFace);
8654                   for(std::size_t j=0;j<nbOfEdgesInFace;j++)
8655                     {
8656                       std::pair<int,int> p1(bgFace[j],bgFace[(j+1)%nbOfEdgesInFace]);
8657                       std::pair<int,int> p2(p1.second,p1.first);
8658                       if(std::find(edgesOK.begin(),edgesOK.end(),p1)!=edgesOK.end())
8659                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8660                       if(std::find(edgesFinished.begin(),edgesFinished.end(),p1)!=edgesFinished.end() || std::find(edgesFinished.begin(),edgesFinished.end(),p2)!=edgesFinished.end())
8661                         { std::ostringstream oss; oss << "Face #" << j << " of polyhedron looks bad !"; throw INTERP_KERNEL::Exception(oss.str().c_str()); }
8662                       std::list< std::pair<int,int> >::iterator it=std::find(edgesOK.begin(),edgesOK.end(),p2);
8663                       if(it!=edgesOK.end())
8664                         {
8665                           edgesOK.erase(it);
8666                           edgesFinished.push_back(p1);
8667                         }
8668                       else
8669                         edgesOK.push_back(p1);
8670                     }
8671                 }
8672             }
8673           bgFace=endFace+1;
8674         }
8675       if(smthChanged==0)
8676         { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired !"); }
8677     }
8678   if(!edgesOK.empty())
8679     { throw INTERP_KERNEL::Exception("The polyhedron looks too bad to be repaired : Some edges are shared only once !"); }
8680   if(INTERP_KERNEL::calculateVolumeForPolyh2<int,INTERP_KERNEL::ALL_C_MODE>(begin,(int)std::distance(begin,end),coords)<-EPS_FOR_POLYH_ORIENTATION)
8681     {//not lucky ! The first face was not correctly oriented : reorient all faces...
8682       bgFace=begin;
8683       for(std::size_t i=0;i<nbOfFaces;i++)
8684         {
8685           endFace=std::find(bgFace+1,end,-1);
8686           std::reverse(bgFace+1,endFace);
8687           bgFace=endFace+1;
8688         }
8689     }
8690 }
8691
8692 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshLinear(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8693 {
8694   int nbOfNodesExpected(skin->getNumberOfNodes());
8695   const int *n2oPtr(n2o->getConstPointer());
8696   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8697   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8698   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8699   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8700   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8701   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8702   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_POLYGON;
8703   if(nbOfNodesExpected<1)
8704     return ret.retn();
8705   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8706   *work++=n2oPtr[prevNode];
8707   for(int i=1;i<nbOfNodesExpected;i++)
8708     {
8709       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==3)
8710         {
8711           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8712           conn.erase(prevNode);
8713           if(conn.size()==1)
8714             {
8715               int curNode(*(conn.begin()));
8716               *work++=n2oPtr[curNode];
8717               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8718               shar.erase(prevCell);
8719               if(shar.size()==1)
8720                 {
8721                   prevCell=*(shar.begin());
8722                   prevNode=curNode;
8723                 }
8724               else
8725                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 2 !");
8726             }
8727           else
8728             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected 1 !");
8729         }
8730       else
8731         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshLinear : presence of unexpected cell !");
8732     }
8733   return ret.retn();
8734 }
8735
8736 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMeshQuadratic(const MEDCouplingUMesh *skin, const DataArrayInt *n2o) const
8737 {
8738   int nbOfNodesExpected(skin->getNumberOfNodes());
8739   int nbOfTurn(nbOfNodesExpected/2);
8740   const int *n2oPtr(n2o->getConstPointer());
8741   MCAuto<DataArrayInt> revNodal(DataArrayInt::New()),revNodalI(DataArrayInt::New());
8742   skin->getReverseNodalConnectivity(revNodal,revNodalI);
8743   const int *revNodalPtr(revNodal->getConstPointer()),*revNodalIPtr(revNodalI->getConstPointer());
8744   const int *nodalPtr(skin->getNodalConnectivity()->getConstPointer());
8745   const int *nodalIPtr(skin->getNodalConnectivityIndex()->getConstPointer());
8746   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfNodesExpected+1,1);
8747   int *work(ret->getPointer());  *work++=INTERP_KERNEL::NORM_QPOLYG;
8748   if(nbOfNodesExpected<1)
8749     return ret.retn();
8750   int prevCell(0),prevNode(nodalPtr[nodalIPtr[0]+1]);
8751   *work=n2oPtr[prevNode]; work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[0]+3]]; work++;
8752   for(int i=1;i<nbOfTurn;i++)
8753     {
8754       if(nodalIPtr[prevCell+1]-nodalIPtr[prevCell]==4)
8755         {
8756           std::set<int> conn(nodalPtr+nodalIPtr[prevCell]+1,nodalPtr+nodalIPtr[prevCell]+3);
8757           conn.erase(prevNode);
8758           if(conn.size()==1)
8759             {
8760               int curNode(*(conn.begin()));
8761               *work=n2oPtr[curNode];
8762               std::set<int> shar(revNodalPtr+revNodalIPtr[curNode],revNodalPtr+revNodalIPtr[curNode+1]);
8763               shar.erase(prevCell);
8764               if(shar.size()==1)
8765                 {
8766                   int curCell(*(shar.begin()));
8767                   work[nbOfTurn]=n2oPtr[nodalPtr[nodalIPtr[curCell]+3]];
8768                   prevCell=curCell;
8769                   prevNode=curNode;
8770                   work++;
8771                 }
8772               else
8773                 throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 2 !");
8774             }
8775           else
8776             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected 1 !");
8777         }
8778       else
8779         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMeshQuadratic : presence of unexpected cell !");
8780     }
8781   return ret.retn();
8782 }
8783
8784 /*!
8785  * This method makes the assumption spacedimension == meshdimension == 2.
8786  * This method works only for linear cells.
8787  * 
8788  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYGON in pos#0)
8789  */
8790 DataArrayInt *MEDCouplingUMesh::buildUnionOf2DMesh() const
8791 {
8792   if(getMeshDimension()!=2 || getSpaceDimension()!=2)
8793     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : meshdimension, spacedimension must be equal to 2 !");
8794   MCAuto<MEDCouplingUMesh> skin(computeSkin());
8795   int oldNbOfNodes(skin->getNumberOfNodes());
8796   MCAuto<DataArrayInt> o2n(skin->zipCoordsTraducer());
8797   int nbOfNodesExpected(skin->getNumberOfNodes());
8798   MCAuto<DataArrayInt> n2o(o2n->invertArrayO2N2N2O(oldNbOfNodes));
8799   int nbCells(skin->getNumberOfCells());
8800   if(nbCells==nbOfNodesExpected)
8801     return buildUnionOf2DMeshLinear(skin,n2o);
8802   else if(2*nbCells==nbOfNodesExpected)
8803     return buildUnionOf2DMeshQuadratic(skin,n2o);
8804   else
8805     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf2DMesh : the mesh 2D in input appears to be not in a single part of a 2D mesh !");
8806 }
8807
8808 /*!
8809  * This method makes the assumption spacedimension == meshdimension == 3.
8810  * This method works only for linear cells.
8811  * 
8812  * \return a newly allocated array containing the connectivity of a polygon type enum included (NORM_POLYHED in pos#0)
8813  */
8814 DataArrayInt *MEDCouplingUMesh::buildUnionOf3DMesh() const
8815 {
8816   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
8817     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildUnionOf3DMesh : meshdimension, spacedimension must be equal to 2 !");
8818   MCAuto<MEDCouplingUMesh> m=computeSkin();
8819   const int *conn=m->getNodalConnectivity()->getConstPointer();
8820   const int *connI=m->getNodalConnectivityIndex()->getConstPointer();
8821   int nbOfCells=m->getNumberOfCells();
8822   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(m->getNodalConnectivity()->getNumberOfTuples(),1);
8823   int *work=ret->getPointer();  *work++=INTERP_KERNEL::NORM_POLYHED;
8824   if(nbOfCells<1)
8825     return ret.retn();
8826   work=std::copy(conn+connI[0]+1,conn+connI[1],work);
8827   for(int i=1;i<nbOfCells;i++)
8828     {
8829       *work++=-1;
8830       work=std::copy(conn+connI[i]+1,conn+connI[i+1],work);
8831     }
8832   return ret.retn();
8833 }
8834
8835 /*!
8836  * \brief Creates a graph of cell neighbors
8837  *  \return MEDCouplingSkyLineArray * - an sky line array the user should delete.
8838  *  In the sky line array, graph arcs are stored in terms of (index,value) notation.
8839  *  For example
8840  *  - index:  0 3 5 6 6
8841  *  - value:  1 2 3 2 3 3
8842  *  means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8843  *  Arcs are not doubled but reflexive (1,1) arcs are present for each cell
8844  */
8845 MEDCouplingSkyLineArray *MEDCouplingUMesh::generateGraph() const
8846 {
8847   checkConnectivityFullyDefined();
8848
8849   int meshDim = this->getMeshDimension();
8850   MEDCoupling::DataArrayInt* indexr=MEDCoupling::DataArrayInt::New();
8851   MEDCoupling::DataArrayInt* revConn=MEDCoupling::DataArrayInt::New();
8852   this->getReverseNodalConnectivity(revConn,indexr);
8853   const int* indexr_ptr=indexr->getConstPointer();
8854   const int* revConn_ptr=revConn->getConstPointer();
8855
8856   const MEDCoupling::DataArrayInt* index;
8857   const MEDCoupling::DataArrayInt* conn;
8858   conn=this->getNodalConnectivity(); // it includes a type as the 1st element!!!
8859   index=this->getNodalConnectivityIndex();
8860   int nbCells=this->getNumberOfCells();
8861   const int* index_ptr=index->getConstPointer();
8862   const int* conn_ptr=conn->getConstPointer();
8863
8864   //creating graph arcs (cell to cell relations)
8865   //arcs are stored in terms of (index,value) notation
8866   // 0 3 5 6 6
8867   // 1 2 3 2 3 3
8868   // means 6 arcs (0,1), (0,2), (0,3), (1,2), (1,3), (2,3)
8869   // in present version arcs are not doubled but reflexive (1,1) arcs are present for each cell
8870
8871   //warning here one node have less than or equal effective number of cell with it
8872   //but cell could have more than effective nodes
8873   //because other equals nodes in other domain (with other global inode)
8874   std::vector <int> cell2cell_index(nbCells+1,0);
8875   std::vector <int> cell2cell;
8876   cell2cell.reserve(3*nbCells);
8877
8878   for (int icell=0; icell<nbCells;icell++)
8879     {
8880       std::map<int,int > counter;
8881       for (int iconn=index_ptr[icell]+1; iconn<index_ptr[icell+1];iconn++)
8882         {
8883           int inode=conn_ptr[iconn];
8884           for (int iconnr=indexr_ptr[inode]; iconnr<indexr_ptr[inode+1];iconnr++)
8885             {
8886               int icell2=revConn_ptr[iconnr];
8887               std::map<int,int>::iterator iter=counter.find(icell2);
8888               if (iter!=counter.end()) (iter->second)++;
8889               else counter.insert(std::make_pair(icell2,1));
8890             }
8891         }
8892       for (std::map<int,int>::const_iterator iter=counter.begin();
8893            iter!=counter.end(); iter++)
8894         if (iter->second >= meshDim)
8895           {
8896             cell2cell_index[icell+1]++;
8897             cell2cell.push_back(iter->first);
8898           }
8899     }
8900   indexr->decrRef();
8901   revConn->decrRef();
8902   cell2cell_index[0]=0;
8903   for (int icell=0; icell<nbCells;icell++)
8904     cell2cell_index[icell+1]=cell2cell_index[icell]+cell2cell_index[icell+1];
8905
8906   //filling up index and value to create skylinearray structure
8907   MEDCouplingSkyLineArray* array=new MEDCouplingSkyLineArray(cell2cell_index,cell2cell);
8908   return array;
8909 }
8910
8911 /*!
8912  * This method put in zip format into parameter 'zipFrmt' in full interlace mode.
8913  * This format is often asked by INTERP_KERNEL algorithms to avoid many indirections into coordinates array.
8914  */
8915 void MEDCouplingUMesh::FillInCompact3DMode(int spaceDim, int nbOfNodesInCell, const int *conn, const double *coo, double *zipFrmt)
8916 {
8917   double *w=zipFrmt;
8918   if(spaceDim==3)
8919     for(int i=0;i<nbOfNodesInCell;i++)
8920       w=std::copy(coo+3*conn[i],coo+3*conn[i]+3,w);
8921   else if(spaceDim==2)
8922     {
8923       for(int i=0;i<nbOfNodesInCell;i++)
8924         {
8925           w=std::copy(coo+2*conn[i],coo+2*conn[i]+2,w);
8926           *w++=0.;
8927         }
8928     }
8929   else
8930     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::FillInCompact3DMode : Invalid spaceDim specified : must be 2 or 3 !");
8931 }
8932
8933 void MEDCouplingUMesh::writeVTKLL(std::ostream& ofs, const std::string& cellData, const std::string& pointData, DataArrayByte *byteData) const
8934 {
8935   int nbOfCells=getNumberOfCells();
8936   if(nbOfCells<=0)
8937     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::writeVTK : the unstructured mesh has no cells !");
8938   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};
8939   ofs << "  <" << getVTKDataSetType() << ">\n";
8940   ofs << "    <Piece NumberOfPoints=\"" << getNumberOfNodes() << "\" NumberOfCells=\"" << nbOfCells << "\">\n";
8941   ofs << "      <PointData>\n" << pointData << std::endl;
8942   ofs << "      </PointData>\n";
8943   ofs << "      <CellData>\n" << cellData << std::endl;
8944   ofs << "      </CellData>\n";
8945   ofs << "      <Points>\n";
8946   if(getSpaceDimension()==3)
8947     _coords->writeVTK(ofs,8,"Points",byteData);
8948   else
8949     {
8950       MCAuto<DataArrayDouble> coo=_coords->changeNbOfComponents(3,0.);
8951       coo->writeVTK(ofs,8,"Points",byteData);
8952     }
8953   ofs << "      </Points>\n";
8954   ofs << "      <Cells>\n";
8955   const int *cPtr=_nodal_connec->getConstPointer();
8956   const int *cIPtr=_nodal_connec_index->getConstPointer();
8957   MCAuto<DataArrayInt> faceoffsets=DataArrayInt::New(); faceoffsets->alloc(nbOfCells,1);
8958   MCAuto<DataArrayInt> types=DataArrayInt::New(); types->alloc(nbOfCells,1);
8959   MCAuto<DataArrayInt> offsets=DataArrayInt::New(); offsets->alloc(nbOfCells,1);
8960   MCAuto<DataArrayInt> connectivity=DataArrayInt::New(); connectivity->alloc(_nodal_connec->getNumberOfTuples()-nbOfCells,1);
8961   int *w1=faceoffsets->getPointer(),*w2=types->getPointer(),*w3=offsets->getPointer(),*w4=connectivity->getPointer();
8962   int szFaceOffsets=0,szConn=0;
8963   for(int i=0;i<nbOfCells;i++,w1++,w2++,w3++)
8964     {
8965       *w2=cPtr[cIPtr[i]];
8966       if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]!=INTERP_KERNEL::NORM_POLYHED)
8967         {
8968           *w1=-1;
8969           *w3=szConn+cIPtr[i+1]-cIPtr[i]-1; szConn+=cIPtr[i+1]-cIPtr[i]-1;
8970           w4=std::copy(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],w4);
8971         }
8972       else
8973         {
8974           int deltaFaceOffset=cIPtr[i+1]-cIPtr[i]+1;
8975           *w1=szFaceOffsets+deltaFaceOffset; szFaceOffsets+=deltaFaceOffset;
8976           std::set<int> c(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1]); c.erase(-1);
8977           *w3=szConn+(int)c.size(); szConn+=(int)c.size();
8978           w4=std::copy(c.begin(),c.end(),w4);
8979         }
8980     }
8981   types->transformWithIndArr(PARAMEDMEM2VTKTYPETRADUCER,PARAMEDMEM2VTKTYPETRADUCER+INTERP_KERNEL::NORM_MAXTYPE+1);
8982   types->writeVTK(ofs,8,"UInt8","types",byteData);
8983   offsets->writeVTK(ofs,8,"Int32","offsets",byteData);
8984   if(szFaceOffsets!=0)
8985     {//presence of Polyhedra
8986       connectivity->reAlloc(szConn);
8987       faceoffsets->writeVTK(ofs,8,"Int32","faceoffsets",byteData);
8988       MCAuto<DataArrayInt> faces=DataArrayInt::New(); faces->alloc(szFaceOffsets,1);
8989       w1=faces->getPointer();
8990       for(int i=0;i<nbOfCells;i++)
8991         if((INTERP_KERNEL::NormalizedCellType)cPtr[cIPtr[i]]==INTERP_KERNEL::NORM_POLYHED)
8992           {
8993             int nbFaces=std::count(cPtr+cIPtr[i]+1,cPtr+cIPtr[i+1],-1)+1;
8994             *w1++=nbFaces;
8995             const int *w6=cPtr+cIPtr[i]+1,*w5=0;
8996             for(int j=0;j<nbFaces;j++)
8997               {
8998                 w5=std::find(w6,cPtr+cIPtr[i+1],-1);
8999                 *w1++=(int)std::distance(w6,w5);
9000                 w1=std::copy(w6,w5,w1);
9001                 w6=w5+1;
9002               }
9003           }
9004       faces->writeVTK(ofs,8,"Int32","faces",byteData);
9005     }
9006   connectivity->writeVTK(ofs,8,"Int32","connectivity",byteData);
9007   ofs << "      </Cells>\n";
9008   ofs << "    </Piece>\n";
9009   ofs << "  </" << getVTKDataSetType() << ">\n";
9010 }
9011
9012 void MEDCouplingUMesh::reprQuickOverview(std::ostream& stream) const
9013 {
9014   stream << "MEDCouplingUMesh C++ instance at " << this << ". Name : \"" << getName() << "\".";
9015   if(_mesh_dim==-2)
9016     { stream << " Not set !"; return ; }
9017   stream << " Mesh dimension : " << _mesh_dim << ".";
9018   if(_mesh_dim==-1)
9019     return ;
9020   if(!_coords)
9021     { stream << " No coordinates set !"; return ; }
9022   if(!_coords->isAllocated())
9023     { stream << " Coordinates set but not allocated !"; return ; }
9024   stream << " Space dimension : " << _coords->getNumberOfComponents() << "." << std::endl;
9025   stream << "Number of nodes : " << _coords->getNumberOfTuples() << ".";
9026   if(!_nodal_connec_index)
9027     { stream << std::endl << "Nodal connectivity NOT set !"; return ; }
9028   if(!_nodal_connec_index->isAllocated())
9029     { stream << std::endl << "Nodal connectivity set but not allocated !"; return ; }
9030   int lgth=_nodal_connec_index->getNumberOfTuples();
9031   int cpt=_nodal_connec_index->getNumberOfComponents();
9032   if(cpt!=1 || lgth<1)
9033     return ;
9034   stream << std::endl << "Number of cells : " << lgth-1 << ".";
9035 }
9036
9037 std::string MEDCouplingUMesh::getVTKDataSetType() const
9038 {
9039   return std::string("UnstructuredGrid");
9040 }
9041
9042 std::string MEDCouplingUMesh::getVTKFileExtension() const
9043 {
9044   return std::string("vtu");
9045 }
9046
9047 /*!
9048  * Partitions the first given 2D mesh using the second given 2D mesh as a tool, and
9049  * returns a result mesh constituted by polygons.
9050  * Thus the final result contains all nodes from m1 plus new nodes. However it doesn't necessarily contains
9051  * all nodes from m2.
9052  * The meshes should be in 2D space. In
9053  * addition, returns two arrays mapping cells of the result mesh to cells of the input
9054  * meshes.
9055  *  \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
9056  *                      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)
9057  *  \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
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] eps - precision used to detect coincident mesh entities.
9060  *  \param [out] cellNb1 - a new instance of DataArrayInt holding for each result
9061  *         cell an id of the cell of \a m1 it comes from. The caller is to delete
9062  *         this array using decrRef() as it is no more needed.
9063  *  \param [out] cellNb2 - a new instance of DataArrayInt holding for each result
9064  *         cell an id of the cell of \a m2 it comes from. -1 value means that a
9065  *         result cell comes from a cell (or part of cell) of \a m1 not overlapped by
9066  *         any cell of \a m2. The caller is to delete this array using decrRef() as
9067  *         it is no more needed.  
9068  *  \return MEDCouplingUMesh * - the result 2D mesh which is a new instance of
9069  *         MEDCouplingUMesh. The caller is to delete this mesh using decrRef() as it
9070  *         is no more needed.  
9071  *  \throw If the coordinates array is not set in any of the meshes.
9072  *  \throw If the nodal connectivity of cells is not defined in any of the meshes.
9073  *  \throw If any of the meshes is not a 2D mesh in 2D space.
9074  *
9075  *  \sa conformize2D, mergeNodes
9076  */
9077 MEDCouplingUMesh *MEDCouplingUMesh::Intersect2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
9078                                                       double eps, DataArrayInt *&cellNb1, DataArrayInt *&cellNb2)
9079 {
9080   if(!m1 || !m2)
9081     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes : input meshes must be not NULL !");
9082   m1->checkFullyDefined();
9083   m2->checkFullyDefined();
9084   if(m1->getMeshDimension()!=2 || m1->getSpaceDimension()!=2 || m2->getMeshDimension()!=2 || m2->getSpaceDimension()!=2)
9085     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshes works on umeshes m1 AND m2  with meshdim equal to 2 and spaceDim equal to 2 too!");
9086
9087   // Step 1: compute all edge intersections (new nodes)
9088   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9089   MEDCouplingUMesh *m1Desc=0,*m2Desc=0; // descending connec. meshes
9090   DataArrayInt *desc1=0,*descIndx1=0,*revDesc1=0,*revDescIndx1=0,*desc2=0,*descIndx2=0,*revDesc2=0,*revDescIndx2=0;
9091   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9092   IntersectDescending2DMeshes(m1,m2,eps,intersectEdge1,colinear2, subDiv2,
9093                               m1Desc,desc1,descIndx1,revDesc1,revDescIndx1,
9094                               addCoo, m2Desc,desc2,descIndx2,revDesc2,revDescIndx2);
9095   revDesc1->decrRef(); revDescIndx1->decrRef(); revDesc2->decrRef(); revDescIndx2->decrRef();
9096   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(desc2),dd4(descIndx2);
9097   MCAuto<MEDCouplingUMesh> dd5(m1Desc),dd6(m2Desc);
9098
9099   // Step 2: re-order newly created nodes according to the ordering found in m2
9100   std::vector< std::vector<int> > intersectEdge2;
9101   BuildIntersectEdges(m1Desc,m2Desc,addCoo,subDiv2,intersectEdge2);
9102   subDiv2.clear(); dd5=0; dd6=0;
9103
9104   // Step 3:
9105   std::vector<int> cr,crI; //no DataArrayInt because interface with Geometric2D
9106   std::vector<int> cNb1,cNb2; //no DataArrayInt because interface with Geometric2D
9107   BuildIntersecting2DCellsFromEdges(eps,m1,desc1->getConstPointer(),descIndx1->getConstPointer(),intersectEdge1,colinear2,m2,desc2->getConstPointer(),descIndx2->getConstPointer(),intersectEdge2,addCoo,
9108                                     /* outputs -> */addCoordsQuadratic,cr,crI,cNb1,cNb2);
9109
9110   // Step 4: Prepare final result:
9111   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9112   addCooDa->alloc((int)(addCoo.size())/2,2);
9113   std::copy(addCoo.begin(),addCoo.end(),addCooDa->getPointer());
9114   MCAuto<DataArrayDouble> addCoordsQuadraticDa(DataArrayDouble::New());
9115   addCoordsQuadraticDa->alloc((int)(addCoordsQuadratic.size())/2,2);
9116   std::copy(addCoordsQuadratic.begin(),addCoordsQuadratic.end(),addCoordsQuadraticDa->getPointer());
9117   std::vector<const DataArrayDouble *> coordss(4);
9118   coordss[0]=m1->getCoords(); coordss[1]=m2->getCoords(); coordss[2]=addCooDa; coordss[3]=addCoordsQuadraticDa;
9119   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coordss));
9120   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("Intersect2D",2));
9121   MCAuto<DataArrayInt> conn(DataArrayInt::New()); conn->alloc((int)cr.size(),1); std::copy(cr.begin(),cr.end(),conn->getPointer());
9122   MCAuto<DataArrayInt> connI(DataArrayInt::New()); connI->alloc((int)crI.size(),1); std::copy(crI.begin(),crI.end(),connI->getPointer());
9123   MCAuto<DataArrayInt> c1(DataArrayInt::New()); c1->alloc((int)cNb1.size(),1); std::copy(cNb1.begin(),cNb1.end(),c1->getPointer());
9124   MCAuto<DataArrayInt> c2(DataArrayInt::New()); c2->alloc((int)cNb2.size(),1); std::copy(cNb2.begin(),cNb2.end(),c2->getPointer());
9125   ret->setConnectivity(conn,connI,true);
9126   ret->setCoords(coo);
9127   cellNb1=c1.retn(); cellNb2=c2.retn();
9128   return ret.retn();
9129 }
9130
9131 /// @cond INTERNAL
9132
9133 bool IsColinearOfACellOf(const std::vector< std::vector<int> >& intersectEdge1, const std::vector<int>& candidates, int start, int stop, int& retVal)
9134 {
9135   if(candidates.empty())
9136     return false;
9137   for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
9138     {
9139       const std::vector<int>& pool(intersectEdge1[*it]);
9140       int tmp[2]; tmp[0]=start; tmp[1]=stop;
9141       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9142         {
9143           retVal=*it+1;
9144           return true;
9145         }
9146       tmp[0]=stop; tmp[1]=start;
9147       if(std::search(pool.begin(),pool.end(),tmp,tmp+2)!=pool.end())
9148         {
9149           retVal=-*it-1;
9150           return true;
9151         }
9152     }
9153   return false;
9154 }
9155
9156 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,
9157                                      MCAuto<DataArrayInt>& idsInRetColinear, MCAuto<DataArrayInt>& idsInMesh1DForIdsInRetColinear)
9158 {
9159   idsInRetColinear=DataArrayInt::New(); idsInRetColinear->alloc(0,1);
9160   idsInMesh1DForIdsInRetColinear=DataArrayInt::New(); idsInMesh1DForIdsInRetColinear->alloc(0,1);
9161   int nCells(mesh1D->getNumberOfCells());
9162   if(nCells!=(int)intersectEdge2.size())
9163     throw INTERP_KERNEL::Exception("BuildMesh1DCutFrom : internal error # 1 !");
9164   const DataArrayDouble *coo2(mesh1D->getCoords());
9165   const int *c(mesh1D->getNodalConnectivity()->begin()),*ci(mesh1D->getNodalConnectivityIndex()->begin());
9166   const double *coo2Ptr(coo2->begin());
9167   int offset1(coords1->getNumberOfTuples());
9168   int offset2(offset1+coo2->getNumberOfTuples());
9169   int offset3(offset2+addCoo.size()/2);
9170   std::vector<double> addCooQuad;
9171   MCAuto<DataArrayInt> cOut(DataArrayInt::New()),ciOut(DataArrayInt::New()); cOut->alloc(0,1); ciOut->alloc(1,1); ciOut->setIJ(0,0,0);
9172   int tmp[4],cicnt(0),kk(0);
9173   for(int i=0;i<nCells;i++)
9174     {
9175       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
9176       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coo2Ptr,m));
9177       const std::vector<int>& subEdges(intersectEdge2[i]);
9178       int nbSubEdge(subEdges.size()/2);
9179       for(int j=0;j<nbSubEdge;j++,kk++)
9180         {
9181           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));
9182           MCAuto<INTERP_KERNEL::Edge> e2(e->buildEdgeLyingOnMe(n1,n2));
9183           INTERP_KERNEL::Edge *e2Ptr(e2);
9184           std::map<int,int>::const_iterator itm;
9185           if(dynamic_cast<INTERP_KERNEL::EdgeArcCircle *>(e2Ptr))
9186             {
9187               tmp[0]=INTERP_KERNEL::NORM_SEG3;
9188               itm=mergedNodes.find(subEdges[2*j]);
9189               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9190               itm=mergedNodes.find(subEdges[2*j+1]);
9191               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9192               tmp[3]=offset3+(int)addCooQuad.size()/2;
9193               double tmp2[2];
9194               e2->getBarycenter(tmp2); addCooQuad.insert(addCooQuad.end(),tmp2,tmp2+2);
9195               cicnt+=4;
9196               cOut->insertAtTheEnd(tmp,tmp+4);
9197               ciOut->pushBackSilent(cicnt);
9198             }
9199           else
9200             {
9201               tmp[0]=INTERP_KERNEL::NORM_SEG2;
9202               itm=mergedNodes.find(subEdges[2*j]);
9203               tmp[1]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j];
9204               itm=mergedNodes.find(subEdges[2*j+1]);
9205               tmp[2]=itm!=mergedNodes.end()?(*itm).second:subEdges[2*j+1];
9206               cicnt+=3;
9207               cOut->insertAtTheEnd(tmp,tmp+3);
9208               ciOut->pushBackSilent(cicnt);
9209             }
9210           int tmp00;
9211           if(IsColinearOfACellOf(intersectEdge1,colinear2[i],tmp[1],tmp[2],tmp00))
9212             {
9213               idsInRetColinear->pushBackSilent(kk);
9214               idsInMesh1DForIdsInRetColinear->pushBackSilent(tmp00);
9215             }
9216         }
9217       e->decrRef();
9218     }
9219   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New(mesh1D->getName(),1));
9220   ret->setConnectivity(cOut,ciOut,true);
9221   MCAuto<DataArrayDouble> arr3(DataArrayDouble::New());
9222   arr3->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9223   MCAuto<DataArrayDouble> arr4(DataArrayDouble::New()); arr4->useArray(&addCooQuad[0],false,C_DEALLOC,(int)addCooQuad.size()/2,2);
9224   std::vector<const DataArrayDouble *> coordss(4);
9225   coordss[0]=coords1; coordss[1]=mesh1D->getCoords(); coordss[2]=arr3; coordss[3]=arr4;
9226   MCAuto<DataArrayDouble> arr(DataArrayDouble::Aggregate(coordss));
9227   ret->setCoords(arr);
9228   return ret.retn();
9229 }
9230
9231 MEDCouplingUMesh *BuildRefined2DCellLinear(const DataArrayDouble *coords, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9232 {
9233   std::vector<int> allEdges;
9234   for(const int *it2(descBg);it2!=descEnd;it2++)
9235     {
9236       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9237       if(*it2>0)
9238         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9239       else
9240         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9241     }
9242   std::size_t nb(allEdges.size());
9243   if(nb%2!=0)
9244     throw INTERP_KERNEL::Exception("BuildRefined2DCellLinear : internal error 1 !");
9245   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9246   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9247   ret->setCoords(coords);
9248   ret->allocateCells(1);
9249   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9250   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9251     connOut[kk]=allEdges[2*kk];
9252   ret->insertNextCell(INTERP_KERNEL::NORM_POLYGON,connOut.size(),&connOut[0]);
9253   return ret.retn();
9254 }
9255
9256 MEDCouplingUMesh *BuildRefined2DCellQuadratic(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9257 {
9258   const int *c(mesh2D->getNodalConnectivity()->begin()),*ci(mesh2D->getNodalConnectivityIndex()->begin());
9259   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[cellIdInMesh2D]]));
9260   std::size_t ii(0);
9261   unsigned sz(cm.getNumberOfSons2(c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1));
9262   if(sz!=std::distance(descBg,descEnd))
9263     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 1 !");
9264   INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]]);
9265   std::vector<int> allEdges,centers;
9266   const double *coordsPtr(coords->begin());
9267   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
9268   int offset(coords->getNumberOfTuples());
9269   for(const int *it2(descBg);it2!=descEnd;it2++,ii++)
9270     {
9271       INTERP_KERNEL::NormalizedCellType typeOfSon;
9272       cm.fillSonCellNodalConnectivity2(ii,c+ci[cellIdInMesh2D]+1,ci[cellIdInMesh2D+1]-ci[cellIdInMesh2D]-1,tmpPtr,typeOfSon);
9273       const std::vector<int>& edge1(intersectEdge1[std::abs(*it2)-1]);
9274       if(*it2>0)
9275         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9276       else
9277         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9278       if(edge1.size()==2)
9279         centers.push_back(tmpPtr[2]);//special case where no subsplit of edge -> reuse the original center.
9280       else
9281         {//the current edge has been subsplit -> create corresponding centers.
9282           std::size_t nbOfCentersToAppend(edge1.size()/2);
9283           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9284           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpPtr,coordsPtr,m));
9285           std::vector<int>::const_iterator it3(allEdges.end()-edge1.size());
9286           for(std::size_t k=0;k<nbOfCentersToAppend;k++)
9287             {
9288               double tmpp[2];
9289               const double *aa(coordsPtr+2*(*it3++));
9290               const double *bb(coordsPtr+2*(*it3++));
9291               ee->getMiddleOfPoints(aa,bb,tmpp);
9292               addCoo->insertAtTheEnd(tmpp,tmpp+2);
9293               centers.push_back(offset+k);
9294             }
9295         }
9296     }
9297   std::size_t nb(allEdges.size());
9298   if(nb%2!=0)
9299     throw INTERP_KERNEL::Exception("BuildRefined2DCellQuadratic : internal error 2 !");
9300   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9301   MCAuto<MEDCouplingUMesh> ret(MEDCouplingUMesh::New("",2));
9302   if(addCoo->empty())
9303     ret->setCoords(coords);
9304   else
9305     {
9306       addCoo->rearrange(2);
9307       addCoo=DataArrayDouble::Aggregate(coords,addCoo);
9308       ret->setCoords(addCoo);
9309     }
9310   ret->allocateCells(1);
9311   std::vector<int> connOut(nbOfEdgesOf2DCellSplit);
9312   for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9313     connOut[kk]=allEdges[2*kk];
9314   connOut.insert(connOut.end(),centers.begin(),centers.end());
9315   ret->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,connOut.size(),&connOut[0]);
9316   return ret.retn();
9317 }
9318
9319 /*!
9320  * This method creates a refinement of a cell in \a mesh2D. Those cell is defined by descending connectivity and the sorted subdivided nodal connectivity
9321  * of those edges.
9322  *
9323  * \param [in] mesh2D - The origin 2D mesh. \b Warning \b coords are not those of \a mesh2D. But mesh2D->getCoords()==coords[:mesh2D->getNumberOfNodes()]
9324  */
9325 MEDCouplingUMesh *BuildRefined2DCell(const DataArrayDouble *coords, const MEDCouplingUMesh *mesh2D, int cellIdInMesh2D, const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1)
9326 {
9327   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(mesh2D->getTypeOfCell(cellIdInMesh2D)));
9328   if(!cm.isQuadratic())
9329     return BuildRefined2DCellLinear(coords,descBg,descEnd,intersectEdge1);
9330   else
9331     return BuildRefined2DCellQuadratic(coords,mesh2D,cellIdInMesh2D,descBg,descEnd,intersectEdge1);
9332 }
9333
9334 void AddCellInMesh2D(MEDCouplingUMesh *mesh2D, const std::vector<int>& conn, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edges)
9335 {
9336   bool isQuad(false);
9337   for(std::vector< MCAuto<INTERP_KERNEL::Edge> >::const_iterator it=edges.begin();it!=edges.end();it++)
9338     {
9339       const INTERP_KERNEL::Edge *ee(*it);
9340       if(dynamic_cast<const INTERP_KERNEL::EdgeArcCircle *>(ee))
9341         isQuad=true;
9342     }
9343   if(!isQuad)
9344     mesh2D->insertNextCell(INTERP_KERNEL::NORM_POLYGON,conn.size(),&conn[0]);
9345   else
9346     {
9347       const double *coo(mesh2D->getCoords()->begin());
9348       std::size_t sz(conn.size());
9349       std::vector<double> addCoo;
9350       std::vector<int> conn2(conn);
9351       int offset(mesh2D->getNumberOfNodes());
9352       for(std::size_t i=0;i<sz;i++)
9353         {
9354           double tmp[2];
9355           edges[(i+1)%sz]->getMiddleOfPoints(coo+2*conn[i],coo+2*conn[(i+1)%sz],tmp);// tony a chier i+1 -> i
9356           addCoo.insert(addCoo.end(),tmp,tmp+2);
9357           conn2.push_back(offset+(int)i);
9358         }
9359       mesh2D->getCoords()->rearrange(1);
9360       mesh2D->getCoords()->pushBackValsSilent(&addCoo[0],&addCoo[0]+addCoo.size());
9361       mesh2D->getCoords()->rearrange(2);
9362       mesh2D->insertNextCell(INTERP_KERNEL::NORM_QPOLYG,conn2.size(),&conn2[0]);
9363     }
9364 }
9365
9366 /*!
9367  * \b WARNING edges in out1 coming from \a splitMesh1D are \b NOT oriented because only used for equation of curve.
9368  *
9369  * This method cuts in 2 parts the input 2D cell given using boundaries description (\a edge1Bis and \a edge1BisPtr) using
9370  * a set of edges defined in \a splitMesh1D.
9371  */
9372 void BuildMesh2DCutInternal2(const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& edge1Bis, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edge1BisPtr,
9373                              std::vector< std::vector<int> >& out0, std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > >& out1)
9374 {
9375   std::size_t nb(edge1Bis.size()/2);
9376   std::size_t nbOfEdgesOf2DCellSplit(nb/2);
9377   int iEnd(splitMesh1D->getNumberOfCells());
9378   if(iEnd==0)
9379     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal2 : internal error ! input 1D mesh must have at least one cell !");
9380   std::size_t ii,jj;
9381   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9382   for(ii=0;ii<nb && edge1Bis[2*ii]!=cSplitPtr[ciSplitPtr[0]+1];ii++);
9383   for(jj=ii;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd-1]+2];jj++);
9384   //
9385   if(jj==nb)
9386     {//the edges splitMesh1D[iStart:iEnd] does not fully cut the current 2D cell -> single output cell
9387       out0.resize(1); out1.resize(1);
9388       std::vector<int>& connOut(out0[0]);
9389       connOut.resize(nbOfEdgesOf2DCellSplit);
9390       std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr(out1[0]);
9391       edgesPtr.resize(nbOfEdgesOf2DCellSplit);
9392       for(std::size_t kk=0;kk<nbOfEdgesOf2DCellSplit;kk++)
9393         {
9394           connOut[kk]=edge1Bis[2*kk];
9395           edgesPtr[kk]=edge1BisPtr[2*kk];
9396         }
9397     }
9398   else
9399     {
9400       // [i,iEnd[ contains the
9401       out0.resize(2); out1.resize(2);
9402       std::vector<int>& connOutLeft(out0[0]);
9403       std::vector<int>& connOutRight(out0[1]);//connOutLeft should end with edge1Bis[2*ii] and connOutRight should end with edge1Bis[2*jj+1]
9404       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eleft(out1[0]);
9405       std::vector< MCAuto<INTERP_KERNEL::Edge> >& eright(out1[1]);
9406       for(std::size_t k=ii;k<jj+1;k++)
9407         { connOutLeft.push_back(edge1Bis[2*k+1]); eleft.push_back(edge1BisPtr[2*k+1]); }
9408       std::vector< MCAuto<INTERP_KERNEL::Edge> > ees(iEnd);
9409       for(int ik=0;ik<iEnd;ik++)
9410         {
9411           std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9412           MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cSplitPtr[ciSplitPtr[ik]],cSplitPtr+ciSplitPtr[ik]+1,splitMesh1D->getCoords()->begin(),m));
9413           ees[ik]=ee;
9414         }
9415       for(int ik=iEnd-1;ik>=0;ik--)
9416         connOutLeft.push_back(cSplitPtr[ciSplitPtr[ik]+1]);
9417       for(std::size_t k=jj+1;k<nbOfEdgesOf2DCellSplit+ii;k++)
9418         { connOutRight.push_back(edge1Bis[2*k+1]); eright.push_back(edge1BisPtr[2*k+1]); }
9419       eleft.insert(eleft.end(),ees.rbegin(),ees.rend());
9420       for(int ik=0;ik<iEnd;ik++)
9421         connOutRight.push_back(cSplitPtr[ciSplitPtr[ik]+2]);
9422       eright.insert(eright.end(),ees.begin(),ees.end());
9423     }
9424 }
9425
9426 /// @endcond
9427
9428 /// @cond INTERNAL
9429
9430 struct CellInfo
9431 {
9432 public:
9433   CellInfo() { }
9434   CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9435 public:
9436   std::vector<int> _edges;
9437   std::vector< MCAuto<INTERP_KERNEL::Edge> > _edges_ptr;
9438 };
9439
9440 CellInfo::CellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr)
9441 {
9442   std::size_t nbe(edges.size());
9443   std::vector<int> edges2(2*nbe); std::vector< MCAuto<INTERP_KERNEL::Edge> > edgesPtr2(2*nbe);
9444   for(std::size_t i=0;i<nbe;i++)
9445     {
9446       edges2[2*i]=edges[i]; edges2[2*i+1]=edges[(i+1)%nbe];
9447       edgesPtr2[2*i]=edgesPtr[(i+1)%nbe]; edgesPtr2[2*i+1]=edgesPtr[(i+1)%nbe];//tony a chier
9448     }
9449   _edges.resize(4*nbe); _edges_ptr.resize(4*nbe);
9450   std::copy(edges2.begin(),edges2.end(),_edges.begin()); std::copy(edges2.begin(),edges2.end(),_edges.begin()+2*nbe);
9451   std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()); std::copy(edgesPtr2.begin(),edgesPtr2.end(),_edges_ptr.begin()+2*nbe);
9452 }
9453
9454 class EdgeInfo
9455 {
9456 public:
9457   EdgeInfo(int istart, int iend, const MCAuto<MEDCouplingUMesh>& mesh):_istart(istart),_iend(iend),_mesh(mesh),_left(-7),_right(-7) { }
9458   EdgeInfo(int istart, int iend, int pos, const MCAuto<INTERP_KERNEL::Edge>& edge):_istart(istart),_iend(iend),_edge(edge),_left(pos),_right(pos+1) { }
9459   bool isInMyRange(int pos) const { return pos>=_istart && pos<_iend; }
9460   void somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9461   void feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const;
9462 private:
9463   int _istart;
9464   int _iend;
9465   MCAuto<MEDCouplingUMesh> _mesh;
9466   MCAuto<INTERP_KERNEL::Edge> _edge;
9467   int _left;
9468   int _right;
9469 };
9470
9471 void EdgeInfo::somethingHappendAt(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9472 {
9473   const MEDCouplingUMesh *mesh(_mesh);
9474   if(mesh)
9475     return ;
9476   if(_right<pos)
9477     return ;
9478   if(_left>pos)
9479     { _left++; _right++; return ; }
9480   if(_right==pos)
9481     {
9482       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9483       if((isLeft && isRight) || (!isLeft && !isRight))
9484         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 1 !");
9485       if(isLeft)
9486         return ;
9487       if(isRight)
9488         {
9489           _right++;
9490           return ;
9491         }
9492     }
9493   if(_left==pos)
9494     {
9495       bool isLeft(std::find(newLeft.begin(),newLeft.end(),_edge)!=newLeft.end()),isRight(std::find(newRight.begin(),newRight.end(),_edge)!=newRight.end());
9496       if((isLeft && isRight) || (!isLeft && !isRight))
9497         throw INTERP_KERNEL::Exception("EdgeInfo::somethingHappendAt : internal error # 2 !");
9498       if(isLeft)
9499         {
9500           _right++;
9501           return ;
9502         }
9503       if(isRight)
9504         {
9505           _left++;
9506           _right++;
9507           return ;
9508         }
9509     }
9510 }
9511
9512 void EdgeInfo::feedEdgeInfoAt(double eps, const MEDCouplingUMesh *mesh2D, int offset, int neighbors[2]) const
9513 {
9514   const MEDCouplingUMesh *mesh(_mesh);
9515   if(!mesh)
9516     {
9517       neighbors[0]=offset+_left; neighbors[1]=offset+_right;
9518     }
9519   else
9520     {// not fully splitting cell case
9521       if(mesh2D->getNumberOfCells()==1)
9522         {//little optimization. 1 cell no need to find in which cell mesh is !
9523           neighbors[0]=offset; neighbors[1]=offset;
9524           return;
9525         }
9526       else
9527         {
9528           MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9529           int cellId(mesh2D->getCellContainingPoint(barys->begin(),eps));
9530           if(cellId==-1)
9531             throw INTERP_KERNEL::Exception("EdgeInfo::feedEdgeInfoAt : internal error !");
9532           neighbors[0]=offset+cellId; neighbors[1]=offset+cellId;
9533         }
9534     }
9535 }
9536
9537 class VectorOfCellInfo
9538 {
9539 public:
9540   VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr);
9541   std::size_t size() const { return _pool.size(); }
9542   int getPositionOf(double eps, const MEDCouplingUMesh *mesh) const;
9543   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);
9544   const std::vector<int>& getConnOf(int pos) const { return get(pos)._edges; }
9545   const std::vector< MCAuto<INTERP_KERNEL::Edge> >& getEdgePtrOf(int pos) const { return get(pos)._edges_ptr; }
9546   MCAuto<MEDCouplingUMesh> getZeMesh() const { return _ze_mesh; }
9547   void feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const;
9548 private:
9549   int getZePosOfEdgeGivenItsGlobalId(int pos) const;
9550   void updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight);
9551   const CellInfo& get(int pos) const;
9552   CellInfo& get(int pos);
9553 private:
9554   std::vector<CellInfo> _pool;
9555   MCAuto<MEDCouplingUMesh> _ze_mesh;
9556   std::vector<EdgeInfo> _edge_info;
9557 };
9558
9559 VectorOfCellInfo::VectorOfCellInfo(const std::vector<int>& edges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& edgesPtr):_pool(1)
9560 {
9561   _pool[0]._edges=edges;
9562   _pool[0]._edges_ptr=edgesPtr;
9563 }
9564
9565 int VectorOfCellInfo::getPositionOf(double eps, const MEDCouplingUMesh *mesh) const
9566 {
9567   if(_pool.empty())
9568     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : empty !");
9569   if(_pool.size()==1)
9570     return 0;
9571   const MEDCouplingUMesh *zeMesh(_ze_mesh);
9572   if(!zeMesh)
9573     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::getPositionOf : null aggregated mesh !");
9574   MCAuto<DataArrayDouble> barys(mesh->computeCellCenterOfMass());
9575   return zeMesh->getCellContainingPoint(barys->begin(),eps);
9576 }
9577
9578 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)
9579 {
9580   get(pos);//to check pos
9581   bool isFast(pos==0 && _pool.size()==1);
9582   std::size_t sz(edges.size());
9583   // dealing with edges
9584   if(sz==1)
9585     _edge_info.push_back(EdgeInfo(istart,iend,mesh1DInCase));
9586   else
9587     _edge_info.push_back(EdgeInfo(istart,iend,pos,edgePtrs[0].back()));
9588   //
9589   std::vector<CellInfo> pool(_pool.size()-1+sz);
9590   for(int i=0;i<pos;i++)
9591     pool[i]=_pool[i];
9592   for(std::size_t j=0;j<sz;j++)
9593     pool[pos+j]=CellInfo(edges[j],edgePtrs[j]);
9594   for(int i=pos+1;i<(int)_pool.size();i++)
9595     pool[i+sz-1]=_pool[i];
9596   _pool=pool;
9597   //
9598   if(sz==2)
9599     updateEdgeInfo(pos,edgePtrs[0],edgePtrs[1]);
9600   //
9601   if(isFast)
9602     {
9603       _ze_mesh=mesh;
9604       return ;
9605     }
9606   //
9607   std::vector< MCAuto<MEDCouplingUMesh> > ms;
9608   if(pos>0)
9609     {
9610       MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(0,pos,true)));
9611       ms.push_back(elt);
9612     }
9613   ms.push_back(mesh);
9614   if(pos<_ze_mesh->getNumberOfCells()-1)
9615   {
9616     MCAuto<MEDCouplingUMesh> elt(static_cast<MEDCouplingUMesh *>(_ze_mesh->buildPartOfMySelfSlice(pos+1,_ze_mesh->getNumberOfCells(),true)));
9617     ms.push_back(elt);
9618   }
9619   std::vector< const MEDCouplingUMesh *> ms2(ms.size());
9620   for(std::size_t j=0;j<ms2.size();j++)
9621     ms2[j]=ms[j];
9622   _ze_mesh=MEDCouplingUMesh::MergeUMeshesOnSameCoords(ms2);
9623 }
9624
9625 void VectorOfCellInfo::feedEdgeInfoAt(double eps, int pos, int offset, int neighbors[2]) const
9626 {
9627   _edge_info[getZePosOfEdgeGivenItsGlobalId(pos)].feedEdgeInfoAt(eps,_ze_mesh,offset,neighbors);
9628 }
9629
9630 int VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId(int pos) const
9631 {
9632   if(pos<0)
9633     throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id ! Must be >=0 !");
9634   int ret(0);
9635   for(std::vector<EdgeInfo>::const_iterator it=_edge_info.begin();it!=_edge_info.end();it++,ret++)
9636     {
9637       if((*it).isInMyRange(pos))
9638         return ret;
9639     }
9640   throw INTERP_KERNEL::Exception("VectorOfCellInfo::getZePosOfEdgeGivenItsGlobalId : invalid id !");
9641 }
9642
9643 void VectorOfCellInfo::updateEdgeInfo(int pos, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newLeft, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& newRight)
9644 {
9645   get(pos);//to check;
9646   if(_edge_info.empty())
9647     return ;
9648   std::size_t sz(_edge_info.size()-1);
9649   for(std::size_t i=0;i<sz;i++)
9650     _edge_info[i].somethingHappendAt(pos,newLeft,newRight);
9651 }
9652
9653 const CellInfo& VectorOfCellInfo::get(int pos) const
9654 {
9655   if(pos<0 || pos>=(int)_pool.size())
9656     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get const : invalid pos !");
9657   return _pool[pos];
9658 }
9659
9660 CellInfo& VectorOfCellInfo::get(int pos)
9661 {
9662   if(pos<0 || pos>=(int)_pool.size())
9663     throw INTERP_KERNEL::Exception("VectorOfCellSplitter::get : invalid pos !");
9664   return _pool[pos];
9665 }
9666
9667 /*!
9668  * Given :
9669  * - a \b closed set of edges ( \a allEdges and \a allEdgesPtr ) that defines the split descending 2D cell.
9670  * - \a splitMesh1D a split 2D curve mesh contained into 2D cell defined above.
9671  *
9672  * This method returns the 2D mesh and feeds \a idsLeftRight using offset.
9673  *
9674  * Algorithm : \a splitMesh1D is cut into contiguous parts. Each contiguous parts will build incrementally the output 2D cells.
9675  *
9676  * \param [in] allEdges a list of pairs (beginNode, endNode). Linked with \a allEdgesPtr to get the equation of edge.
9677  */
9678 MEDCouplingUMesh *BuildMesh2DCutInternal(double eps, const MEDCouplingUMesh *splitMesh1D, const std::vector<int>& allEdges, const std::vector< MCAuto<INTERP_KERNEL::Edge> >& allEdgesPtr, int offset,
9679                                          MCAuto<DataArrayInt>& idsLeftRight)
9680 {
9681   int nbCellsInSplitMesh1D(splitMesh1D->getNumberOfCells());
9682   if(nbCellsInSplitMesh1D==0)
9683     throw INTERP_KERNEL::Exception("BuildMesh2DCutInternal : internal error ! input 1D mesh must have at least one cell !");
9684   const int *cSplitPtr(splitMesh1D->getNodalConnectivity()->begin()),*ciSplitPtr(splitMesh1D->getNodalConnectivityIndex()->begin());
9685   std::size_t nb(allEdges.size()),jj;
9686   if(nb%2!=0)
9687     throw INTERP_KERNEL::Exception("BuildMesh2DCutFrom : internal error 2 !");
9688   std::vector<int> edge1Bis(nb*2);
9689   std::vector< MCAuto<INTERP_KERNEL::Edge> > edge1BisPtr(nb*2);
9690   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin());
9691   std::copy(allEdges.begin(),allEdges.end(),edge1Bis.begin()+nb);
9692   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin());
9693   std::copy(allEdgesPtr.begin(),allEdgesPtr.end(),edge1BisPtr.begin()+nb);
9694   //
9695   idsLeftRight=DataArrayInt::New(); idsLeftRight->alloc(nbCellsInSplitMesh1D*2); idsLeftRight->fillWithValue(-2); idsLeftRight->rearrange(2);
9696   int *idsLeftRightPtr(idsLeftRight->getPointer());
9697   VectorOfCellInfo pool(edge1Bis,edge1BisPtr);
9698   for(int iStart=0;iStart<nbCellsInSplitMesh1D;)
9699     {// split [0:nbCellsInSplitMesh1D) in contiguous parts [iStart:iEnd)
9700       int iEnd(iStart);
9701       for(;iEnd<nbCellsInSplitMesh1D;)
9702         {
9703           for(jj=0;jj<nb && edge1Bis[2*jj+1]!=cSplitPtr[ciSplitPtr[iEnd]+2];jj++);
9704           if(jj!=nb)
9705             break;
9706           else
9707             iEnd++;
9708         }
9709       if(iEnd<nbCellsInSplitMesh1D)
9710         iEnd++;
9711       //
9712       MCAuto<MEDCouplingUMesh> partOfSplitMesh1D(static_cast<MEDCouplingUMesh *>(splitMesh1D->buildPartOfMySelfSlice(iStart,iEnd,1,true)));
9713       int pos(pool.getPositionOf(eps,partOfSplitMesh1D));
9714       //
9715       MCAuto<MEDCouplingUMesh>retTmp(MEDCouplingUMesh::New("",2));
9716       retTmp->setCoords(splitMesh1D->getCoords());
9717       retTmp->allocateCells();
9718
9719       std::vector< std::vector<int> > out0;
9720       std::vector< std::vector< MCAuto<INTERP_KERNEL::Edge> > > out1;
9721
9722       BuildMesh2DCutInternal2(partOfSplitMesh1D,pool.getConnOf(pos),pool.getEdgePtrOf(pos),out0,out1);
9723       for(std::size_t cnt=0;cnt<out0.size();cnt++)
9724         AddCellInMesh2D(retTmp,out0[cnt],out1[cnt]);
9725       pool.setMeshAt(pos,retTmp,iStart,iEnd,partOfSplitMesh1D,out0,out1);
9726       //
9727       iStart=iEnd;
9728     }
9729   for(int mm=0;mm<nbCellsInSplitMesh1D;mm++)
9730     pool.feedEdgeInfoAt(eps,mm,offset,idsLeftRightPtr+2*mm);
9731   return pool.getZeMesh().retn();
9732 }
9733
9734 MEDCouplingUMesh *BuildMesh2DCutFrom(double eps, int cellIdInMesh2D, const MEDCouplingUMesh *mesh2DDesc, const MEDCouplingUMesh *splitMesh1D,
9735                                      const int *descBg, const int *descEnd, const std::vector< std::vector<int> >& intersectEdge1, int offset,
9736                                      MCAuto<DataArrayInt>& idsLeftRight)
9737 {
9738   const int *cdescPtr(mesh2DDesc->getNodalConnectivity()->begin()),*cidescPtr(mesh2DDesc->getNodalConnectivityIndex()->begin());
9739   //
9740   std::vector<int> allEdges;
9741   std::vector< MCAuto<INTERP_KERNEL::Edge> > allEdgesPtr; // for each sub edge in splitMesh2D the uncut Edge object of the original mesh2D
9742   for(const int *it(descBg);it!=descEnd;it++) // for all edges in the descending connectivity of the 2D mesh in relative Fortran mode
9743     {
9744       int edgeId(std::abs(*it)-1);
9745       std::map< MCAuto<INTERP_KERNEL::Node>,int> m;
9746       MCAuto<INTERP_KERNEL::Edge> ee(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)cdescPtr[cidescPtr[edgeId]],cdescPtr+cidescPtr[edgeId]+1,mesh2DDesc->getCoords()->begin(),m));
9747       const std::vector<int>& edge1(intersectEdge1[edgeId]);
9748       if(*it>0)
9749         allEdges.insert(allEdges.end(),edge1.begin(),edge1.end());
9750       else
9751         allEdges.insert(allEdges.end(),edge1.rbegin(),edge1.rend());
9752       std::size_t sz(edge1.size());
9753       for(std::size_t cnt=0;cnt<sz;cnt++)
9754         allEdgesPtr.push_back(ee);
9755     }
9756   //
9757   return BuildMesh2DCutInternal(eps,splitMesh1D,allEdges,allEdgesPtr,offset,idsLeftRight);
9758 }
9759
9760 bool AreEdgeEqual(const double *coo2D, const INTERP_KERNEL::CellModel& typ1, const int *conn1, const INTERP_KERNEL::CellModel& typ2, const int *conn2, double eps)
9761 {
9762   if(!typ1.isQuadratic() && !typ2.isQuadratic())
9763     {//easy case comparison not
9764       return conn1[0]==conn2[0] && conn1[1]==conn2[1];
9765     }
9766   else if(typ1.isQuadratic() && typ2.isQuadratic())
9767     {
9768       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9769       if(!status0)
9770         return false;
9771       if(conn1[2]==conn2[2])
9772         return true;
9773       const double *a(coo2D+2*conn1[2]),*b(coo2D+2*conn2[2]);
9774       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9775       return dist<eps;
9776     }
9777   else
9778     {//only one is quadratic
9779       bool status0(conn1[0]==conn2[0] && conn1[1]==conn2[1]);
9780       if(!status0)
9781         return false;
9782       const double *a(0),*bb(0),*be(0);
9783       if(typ1.isQuadratic())
9784         {
9785           a=coo2D+2*conn1[2]; bb=coo2D+2*conn2[0]; be=coo2D+2*conn2[1];
9786         }
9787       else
9788         {
9789           a=coo2D+2*conn2[2]; bb=coo2D+2*conn1[0]; be=coo2D+2*conn1[1];
9790         }
9791       double b[2]; b[0]=(be[0]+bb[0])/2.; b[1]=(be[1]+bb[1])/2.;
9792       double dist(sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1])));
9793       return dist<eps;
9794     }
9795 }
9796
9797 /*!
9798  * This method returns among the cellIds [ \a candidatesIn2DBg , \a candidatesIn2DEnd ) in \a mesh2DSplit those exactly sharing \a cellIdInMesh1DSplitRelative in \a mesh1DSplit.
9799  * \a mesh2DSplit and \a mesh1DSplit are expected to share the coordinates array.
9800  *
9801  * \param [in] cellIdInMesh1DSplitRelative is in Fortran mode using sign to specify direction.
9802  */
9803 int FindRightCandidateAmong(const MEDCouplingUMesh *mesh2DSplit, const int *candidatesIn2DBg, const int *candidatesIn2DEnd, const MEDCouplingUMesh *mesh1DSplit, int cellIdInMesh1DSplitRelative, double eps)
9804 {
9805   if(candidatesIn2DEnd==candidatesIn2DBg)
9806     throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 1 !");
9807   const double *coo(mesh2DSplit->getCoords()->begin());
9808   if(std::distance(candidatesIn2DBg,candidatesIn2DEnd)==1)
9809     return *candidatesIn2DBg;
9810   int edgeId(std::abs(cellIdInMesh1DSplitRelative)-1);
9811   MCAuto<MEDCouplingUMesh> cur1D(static_cast<MEDCouplingUMesh *>(mesh1DSplit->buildPartOfMySelf(&edgeId,&edgeId+1,true)));
9812   if(cellIdInMesh1DSplitRelative<0)
9813     cur1D->changeOrientationOfCells();
9814   const int *c1D(cur1D->getNodalConnectivity()->begin());
9815   const INTERP_KERNEL::CellModel& ref1DType(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c1D[0]));
9816   for(const int *it=candidatesIn2DBg;it!=candidatesIn2DEnd;it++)
9817     {
9818       MCAuto<MEDCouplingUMesh> cur2D(static_cast<MEDCouplingUMesh *>(mesh2DSplit->buildPartOfMySelf(it,it+1,true)));
9819       const int *c(cur2D->getNodalConnectivity()->begin()),*ci(cur2D->getNodalConnectivityIndex()->begin());
9820       const INTERP_KERNEL::CellModel &cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)c[ci[0]]));
9821       unsigned sz(cm.getNumberOfSons2(c+ci[0]+1,ci[1]-ci[0]-1));
9822       INTERP_KERNEL::AutoPtr<int> tmpPtr(new int[ci[1]-ci[0]]);
9823       for(unsigned it2=0;it2<sz;it2++)
9824         {
9825           INTERP_KERNEL::NormalizedCellType typeOfSon;
9826           cm.fillSonCellNodalConnectivity2(it2,c+ci[0]+1,ci[1]-ci[0]-1,tmpPtr,typeOfSon);
9827           const INTERP_KERNEL::CellModel &curCM(INTERP_KERNEL::CellModel::GetCellModel(typeOfSon));
9828           if(AreEdgeEqual(coo,ref1DType,c1D+1,curCM,tmpPtr,eps))
9829             return *it;
9830         }
9831     }
9832   throw INTERP_KERNEL::Exception("FindRightCandidateAmong : internal error 2 ! Unable to find the edge among split cell !");
9833 }
9834
9835 /// @endcond
9836
9837 /*!
9838  * Partitions the first given 2D mesh using the second given 1D mesh as a tool.
9839  * 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
9840  * and finaly, in case of quadratic polygon the centers of edges new nodes.
9841  * The meshes should be in 2D space. In addition, returns two arrays mapping cells of the resulting mesh to cells of the input.
9842  *
9843  * \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
9844  *                      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)
9845  * \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
9846  *                      you can invoke orderConsecutiveCells1D on \a mesh1D.
9847  * \param [in] eps - precision used to perform intersections and localization operations.
9848  * \param [out] splitMesh2D - the result of the split of \a mesh2D mesh.
9849  * \param [out] splitMesh1D - the result of the split of \a mesh1D mesh.
9850  * \param [out] cellIdInMesh2D - the array that gives for each cell id \a i in \a splitMesh2D the id in \a mesh2D it comes from.
9851  *                               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.
9852  * \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
9853  *                               and the cell in \a splitMesh2D on the right for the 2nt component. -1 means no cell.
9854  *                               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.
9855  *
9856  * \sa Intersect2DMeshes, orderConsecutiveCells1D, conformize2D, mergeNodes
9857  */
9858 void MEDCouplingUMesh::Intersect2DMeshWith1DLine(const MEDCouplingUMesh *mesh2D, const MEDCouplingUMesh *mesh1D, double eps, MEDCouplingUMesh *&splitMesh2D, MEDCouplingUMesh *&splitMesh1D, DataArrayInt *&cellIdInMesh2D, DataArrayInt *&cellIdInMesh1D)
9859 {
9860   if(!mesh2D || !mesh1D)
9861     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine : input meshes must be not NULL !");
9862   mesh2D->checkFullyDefined();
9863   mesh1D->checkFullyDefined();
9864   const std::vector<std::string>& compNames(mesh2D->getCoords()->getInfoOnComponents());
9865   if(mesh2D->getMeshDimension()!=2 || mesh2D->getSpaceDimension()!=2 || mesh1D->getMeshDimension()!=1 || mesh1D->getSpaceDimension()!=2)
9866     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Intersect2DMeshWith1DLine works with mesh2D with spacedim=meshdim=2 and mesh1D with meshdim=1 spaceDim=2 !");
9867   // Step 1: compute all edge intersections (new nodes)
9868   std::vector< std::vector<int> > intersectEdge1, colinear2, subDiv2;
9869   std::vector<double> addCoo,addCoordsQuadratic;  // coordinates of newly created nodes
9870   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
9871   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
9872   //
9873   // Build desc connectivity
9874   DataArrayInt *desc1(DataArrayInt::New()),*descIndx1(DataArrayInt::New()),*revDesc1(DataArrayInt::New()),*revDescIndx1(DataArrayInt::New());
9875   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
9876   MCAuto<MEDCouplingUMesh> m1Desc(mesh2D->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1));
9877   std::map<int,int> mergedNodes;
9878   Intersect1DMeshes(m1Desc,mesh1D,eps,intersectEdge1,colinear2,subDiv2,addCoo,mergedNodes);
9879   // use mergeNodes to fix intersectEdge1
9880   for(std::vector< std::vector<int> >::iterator it0=intersectEdge1.begin();it0!=intersectEdge1.end();it0++)
9881     {
9882       std::size_t n((*it0).size()/2);
9883       int eltStart((*it0)[0]),eltEnd((*it0)[2*n-1]);
9884       std::map<int,int>::const_iterator it1;
9885       it1=mergedNodes.find(eltStart);
9886       if(it1!=mergedNodes.end())
9887         (*it0)[0]=(*it1).second;
9888       it1=mergedNodes.find(eltEnd);
9889       if(it1!=mergedNodes.end())
9890         (*it0)[2*n-1]=(*it1).second;
9891     }
9892   //
9893   MCAuto<DataArrayDouble> addCooDa(DataArrayDouble::New());
9894   addCooDa->useArray(&addCoo[0],false,C_DEALLOC,(int)addCoo.size()/2,2);
9895   // Step 2: re-order newly created nodes according to the ordering found in m2
9896   std::vector< std::vector<int> > intersectEdge2;
9897   BuildIntersectEdges(m1Desc,mesh1D,addCoo,subDiv2,intersectEdge2);
9898   subDiv2.clear();
9899   // Step 3: compute splitMesh1D
9900   MCAuto<DataArrayInt> idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear;
9901   MCAuto<DataArrayInt> ret2(DataArrayInt::New()); ret2->alloc(0,1);
9902   MCAuto<MEDCouplingUMesh> ret1(BuildMesh1DCutFrom(mesh1D,intersectEdge2,mesh2D->getCoords(),addCoo,mergedNodes,colinear2,intersectEdge1,
9903       idsInRet1Colinear,idsInDescMesh2DForIdsInRetColinear));
9904   MCAuto<DataArrayInt> ret3(DataArrayInt::New()); ret3->alloc(ret1->getNumberOfCells()*2,1); ret3->fillWithValue(std::numeric_limits<int>::max()); ret3->rearrange(2);
9905   MCAuto<DataArrayInt> idsInRet1NotColinear(idsInRet1Colinear->buildComplement(ret1->getNumberOfCells()));
9906   // deal with cells in mesh2D that are not cut but only some of their edges are
9907   MCAuto<DataArrayInt> idsInDesc2DToBeRefined(idsInDescMesh2DForIdsInRetColinear->deepCopy());
9908   idsInDesc2DToBeRefined->abs(); idsInDesc2DToBeRefined->applyLin(1,-1);
9909   idsInDesc2DToBeRefined=idsInDesc2DToBeRefined->buildUnique();
9910   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
9911   if(!idsInDesc2DToBeRefined->empty())
9912     {
9913       DataArrayInt *out0(0),*outi0(0);
9914       MEDCouplingUMesh::ExtractFromIndexedArrays(idsInDesc2DToBeRefined->begin(),idsInDesc2DToBeRefined->end(),dd3,dd4,out0,outi0);
9915       MCAuto<DataArrayInt> outi0s(outi0);
9916       out0s=out0;
9917       out0s=out0s->buildUnique();
9918       out0s->sort(true);
9919     }
9920   //
9921   MCAuto<MEDCouplingUMesh> ret1NonCol(static_cast<MEDCouplingUMesh *>(ret1->buildPartOfMySelf(idsInRet1NotColinear->begin(),idsInRet1NotColinear->end())));
9922   MCAuto<DataArrayDouble> baryRet1(ret1NonCol->computeCellCenterOfMass());
9923   MCAuto<DataArrayInt> elts,eltsIndex;
9924   mesh2D->getCellsContainingPoints(baryRet1->begin(),baryRet1->getNumberOfTuples(),eps,elts,eltsIndex);
9925   MCAuto<DataArrayInt> eltsIndex2(eltsIndex->deltaShiftIndex());
9926   MCAuto<DataArrayInt> eltsIndex3(eltsIndex2->findIdsEqual(1));
9927   if(eltsIndex2->count(0)+eltsIndex3->getNumberOfTuples()!=ret1NonCol->getNumberOfCells())
9928     throw INTERP_KERNEL::Exception("Intersect2DMeshWith1DLine : internal error 1 !");
9929   MCAuto<DataArrayInt> cellsToBeModified(elts->buildUnique());
9930   MCAuto<DataArrayInt> untouchedCells(cellsToBeModified->buildComplement(mesh2D->getNumberOfCells()));
9931   if((DataArrayInt *)out0s)
9932     untouchedCells=untouchedCells->buildSubstraction(out0s);//if some edges in ret1 are colinear to descending mesh of mesh2D remove cells from untouched one
9933   std::vector< MCAuto<MEDCouplingUMesh> > outMesh2DSplit;
9934   // OK all is ready to insert in ret2 mesh
9935   if(!untouchedCells->empty())
9936     {// the most easy part, cells in mesh2D not impacted at all
9937       outMesh2DSplit.push_back(static_cast<MEDCouplingUMesh *>(mesh2D->buildPartOfMySelf(untouchedCells->begin(),untouchedCells->end())));
9938       outMesh2DSplit.back()->setCoords(ret1->getCoords());
9939       ret2->pushBackValsSilent(untouchedCells->begin(),untouchedCells->end());
9940     }
9941   if((DataArrayInt *)out0s)
9942     {// here dealing with cells in out0s but not in cellsToBeModified
9943       MCAuto<DataArrayInt> fewModifiedCells(out0s->buildSubstraction(cellsToBeModified));
9944       const int *rdptr(dd3->begin()),*rdiptr(dd4->begin()),*dptr(dd1->begin()),*diptr(dd2->begin());
9945       for(const int *it=fewModifiedCells->begin();it!=fewModifiedCells->end();it++)
9946         {
9947           outMesh2DSplit.push_back(BuildRefined2DCell(ret1->getCoords(),mesh2D,*it,dptr+diptr[*it],dptr+diptr[*it+1],intersectEdge1));
9948           ret1->setCoords(outMesh2DSplit.back()->getCoords());
9949         }
9950       int offset(ret2->getNumberOfTuples());
9951       ret2->pushBackValsSilent(fewModifiedCells->begin(),fewModifiedCells->end());
9952       MCAuto<DataArrayInt> partOfRet3(DataArrayInt::New()); partOfRet3->alloc(2*idsInRet1Colinear->getNumberOfTuples(),1);
9953       partOfRet3->fillWithValue(std::numeric_limits<int>::max()); partOfRet3->rearrange(2);
9954       int kk(0),*ret3ptr(partOfRet3->getPointer());
9955       for(const int *it=idsInDescMesh2DForIdsInRetColinear->begin();it!=idsInDescMesh2DForIdsInRetColinear->end();it++,kk++)
9956         {
9957           int faceId(std::abs(*it)-1);
9958           for(const int *it2=rdptr+rdiptr[faceId];it2!=rdptr+rdiptr[faceId+1];it2++)
9959             {
9960               int tmp(fewModifiedCells->findIdFirstEqual(*it2));
9961               if(tmp!=-1)
9962                 {
9963                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9964                     ret3ptr[2*kk]=tmp+offset;
9965                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9966                     ret3ptr[2*kk+1]=tmp+offset;
9967                 }
9968               else
9969                 {//the current edge is shared by a 2D cell that will be split just after
9970                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],-(*it))!=dptr+diptr[*it2+1])
9971                     ret3ptr[2*kk]=-(*it2+1);
9972                   if(std::find(dptr+diptr[*it2],dptr+diptr[*it2+1],(*it))!=dptr+diptr[*it2+1])
9973                     ret3ptr[2*kk+1]=-(*it2+1);
9974                 }
9975             }
9976         }
9977       m1Desc->setCoords(ret1->getCoords());
9978       ret1NonCol->setCoords(ret1->getCoords());
9979       ret3->setPartOfValues3(partOfRet3,idsInRet1Colinear->begin(),idsInRet1Colinear->end(),0,2,1,true);
9980       if(!outMesh2DSplit.empty())
9981         {
9982           DataArrayDouble *da(outMesh2DSplit.back()->getCoords());
9983           for(std::vector< MCAuto<MEDCouplingUMesh> >::iterator itt=outMesh2DSplit.begin();itt!=outMesh2DSplit.end();itt++)
9984             (*itt)->setCoords(da);
9985         }
9986     }
9987   cellsToBeModified=cellsToBeModified->buildUniqueNotSorted();
9988   for(const int *it=cellsToBeModified->begin();it!=cellsToBeModified->end();it++)
9989     {
9990       MCAuto<DataArrayInt> idsNonColPerCell(elts->findIdsEqual(*it));
9991       idsNonColPerCell->transformWithIndArr(eltsIndex3->begin(),eltsIndex3->end());
9992       MCAuto<DataArrayInt> idsNonColPerCell2(idsInRet1NotColinear->selectByTupleId(idsNonColPerCell->begin(),idsNonColPerCell->end()));
9993       MCAuto<MEDCouplingUMesh> partOfMesh1CuttingCur2DCell(static_cast<MEDCouplingUMesh *>(ret1NonCol->buildPartOfMySelf(idsNonColPerCell->begin(),idsNonColPerCell->end())));
9994       MCAuto<DataArrayInt> partOfRet3;
9995       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));
9996       ret3->setPartOfValues3(partOfRet3,idsNonColPerCell2->begin(),idsNonColPerCell2->end(),0,2,1,true);
9997       outMesh2DSplit.push_back(splitOfOneCell);
9998       for(int i=0;i<splitOfOneCell->getNumberOfCells();i++)
9999         ret2->pushBackSilent(*it);
10000     }
10001   //
10002   std::size_t nbOfMeshes(outMesh2DSplit.size());
10003   std::vector<const MEDCouplingUMesh *> tmp(nbOfMeshes);
10004   for(std::size_t i=0;i<nbOfMeshes;i++)
10005     tmp[i]=outMesh2DSplit[i];
10006   //
10007   ret1->getCoords()->setInfoOnComponents(compNames);
10008   MCAuto<MEDCouplingUMesh> ret2D(MEDCouplingUMesh::MergeUMeshesOnSameCoords(tmp));
10009   // To finish - filter ret3 - std::numeric_limits<int>::max() -> -1 - negate values must be resolved.
10010   ret3->rearrange(1);
10011   MCAuto<DataArrayInt> edgesToDealWith(ret3->findIdsStricltyNegative());
10012   for(const int *it=edgesToDealWith->begin();it!=edgesToDealWith->end();it++)
10013     {
10014       int old2DCellId(-ret3->getIJ(*it,0)-1);
10015       MCAuto<DataArrayInt> candidates(ret2->findIdsEqual(old2DCellId));
10016       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
10017     }
10018   ret3->changeValue(std::numeric_limits<int>::max(),-1);
10019   ret3->rearrange(2);
10020   //
10021   splitMesh1D=ret1.retn();
10022   splitMesh2D=ret2D.retn();
10023   cellIdInMesh2D=ret2.retn();
10024   cellIdInMesh1D=ret3.retn();
10025 }
10026
10027 /**
10028  * Private. Third step of the partitioning algorithm (Intersect2DMeshes): reconstruct full 2D cells from the
10029  * (newly created) nodes corresponding to the edge intersections.
10030  * Output params:
10031  * @param[out] cr, crI connectivity of the resulting mesh
10032  * @param[out] cNb1, cNb2 correspondance arrays giving for the merged mesh the initial cells IDs in m1 / m2
10033  * TODO: describe input parameters
10034  */
10035 void MEDCouplingUMesh::BuildIntersecting2DCellsFromEdges(double eps, const MEDCouplingUMesh *m1, const int *desc1, const int *descIndx1,
10036                                                          const std::vector<std::vector<int> >& intesctEdges1, const std::vector< std::vector<int> >& colinear2,
10037                                                          const MEDCouplingUMesh *m2, const int *desc2, const int *descIndx2, const std::vector<std::vector<int> >& intesctEdges2,
10038                                                          const std::vector<double>& addCoords,
10039                                                          std::vector<double>& addCoordsQuadratic, std::vector<int>& cr, std::vector<int>& crI, std::vector<int>& cNb1, std::vector<int>& cNb2)
10040 {
10041   static const int SPACEDIM=2;
10042   const double *coo1(m1->getCoords()->getConstPointer());
10043   const int *conn1(m1->getNodalConnectivity()->getConstPointer()),*connI1(m1->getNodalConnectivityIndex()->getConstPointer());
10044   int offset1(m1->getNumberOfNodes());
10045   const double *coo2(m2->getCoords()->getConstPointer());
10046   const int *conn2(m2->getNodalConnectivity()->getConstPointer()),*connI2(m2->getNodalConnectivityIndex()->getConstPointer());
10047   int offset2(offset1+m2->getNumberOfNodes());
10048   int offset3(offset2+((int)addCoords.size())/2);
10049   MCAuto<DataArrayDouble> bbox1Arr(m1->getBoundingBoxForBBTree()),bbox2Arr(m2->getBoundingBoxForBBTree());
10050   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10051   // Here a BBTree on 2D-cells, not on segments:
10052   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2->getNumberOfCells(),eps);
10053   int ncell1(m1->getNumberOfCells());
10054   crI.push_back(0);
10055   for(int i=0;i<ncell1;i++)
10056     {
10057       std::vector<int> candidates2;
10058       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10059       std::map<INTERP_KERNEL::Node *,int> mapp;
10060       std::map<int,INTERP_KERNEL::Node *> mappRev;
10061       INTERP_KERNEL::QuadraticPolygon pol1;
10062       INTERP_KERNEL::NormalizedCellType typ=(INTERP_KERNEL::NormalizedCellType)conn1[connI1[i]];
10063       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(typ);
10064       // Populate mapp and mappRev with nodes from the current cell (i) from mesh1 - this also builds the Node* objects:
10065       MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,/* output */mapp,mappRev);
10066       // pol1 is the full cell from mesh2, in QP format, with all the additional intersecting nodes.
10067       pol1.buildFromCrudeDataArray(mappRev,cm.isQuadratic(),conn1+connI1[i]+1,coo1,
10068           desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1);
10069       //
10070       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
10071       std::set<INTERP_KERNEL::Edge *> edgesBoundary2;// store all edges that are on boundary of (pol2 intersect pol1) minus edges on pol1.
10072       INTERP_KERNEL::IteratorOnComposedEdge it1(&pol1);
10073       for(it1.first();!it1.finished();it1.next())
10074         edges1.insert(it1.current()->getPtr());
10075       //
10076       std::map<int,std::vector<INTERP_KERNEL::ElementaryEdge *> > edgesIn2ForShare; // common edges
10077       std::vector<INTERP_KERNEL::QuadraticPolygon> pol2s(candidates2.size());
10078       int ii=0;
10079       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10080         {
10081           INTERP_KERNEL::NormalizedCellType typ2=(INTERP_KERNEL::NormalizedCellType)conn2[connI2[*it2]];
10082           const INTERP_KERNEL::CellModel& cm2=INTERP_KERNEL::CellModel::GetCellModel(typ2);
10083           // Complete mapping with elements coming from the current cell it2 in mesh2:
10084           MEDCouplingUMeshBuildQPFromMesh3(coo1,offset1,coo2,offset2,addCoords,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,/* output */mapp,mappRev);
10085           // pol2 is the new QP in the final merged result.
10086           pol2s[ii].buildFromCrudeDataArray2(mappRev,cm2.isQuadratic(),conn2+connI2[*it2]+1,coo2,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,
10087               pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2, /* output */ edgesIn2ForShare);
10088         }
10089       ii=0;
10090       for(std::vector<int>::const_iterator it2=candidates2.begin();it2!=candidates2.end();it2++,ii++)
10091         {
10092           INTERP_KERNEL::ComposedEdge::InitLocationsWithOther(pol1,pol2s[ii]);
10093           pol2s[ii].updateLocOfEdgeFromCrudeDataArray2(desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,pol1,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,colinear2);
10094           //MEDCouplingUMeshAssignOnLoc(pol1,pol2,desc1+descIndx1[i],desc1+descIndx1[i+1],intesctEdges1,desc2+descIndx2[*it2],desc2+descIndx2[*it2+1],intesctEdges2,colinear2);
10095           pol1.buildPartitionsAbs(pol2s[ii],edges1,edgesBoundary2,mapp,i,*it2,offset3,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10096         }
10097       // Deals with remaining (non-consumed) edges from m1: these are the edges that were never touched
10098       // by m2 but that we still want to keep in the final result.
10099       if(!edges1.empty())
10100         {
10101           try
10102           {
10103               INTERP_KERNEL::QuadraticPolygon::ComputeResidual(pol1,edges1,edgesBoundary2,mapp,offset3,i,addCoordsQuadratic,cr,crI,cNb1,cNb2);
10104           }
10105           catch(INTERP_KERNEL::Exception& e)
10106           {
10107               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();
10108               throw INTERP_KERNEL::Exception(oss.str().c_str());
10109           }
10110         }
10111       for(std::map<int,INTERP_KERNEL::Node *>::const_iterator it=mappRev.begin();it!=mappRev.end();it++)
10112         (*it).second->decrRef();
10113     }
10114 }
10115
10116 /**
10117  * Provides a renumbering of the cells of this (which has to be a piecewise connected 1D line), so that
10118  * the segments of the line are indexed in consecutive order (i.e. cells \a i and \a i+1 are neighbors).
10119  * This doesn't modify the mesh. This method only works using nodal connectivity consideration. Coordinates of nodes are ignored here.
10120  * The caller is to deal with the resulting DataArrayInt.
10121  *  \throw If the coordinate array is not set.
10122  *  \throw If the nodal connectivity of the cells is not defined.
10123  *  \throw If m1 is not a mesh of dimension 2, or m1 is not a mesh of dimension 1
10124  *  \throw If m2 is not a (piecewise) line (i.e. if a point has more than 2 adjacent segments)
10125  *
10126  * \sa DataArrayInt::sortEachPairToMakeALinkedList
10127  */
10128 DataArrayInt *MEDCouplingUMesh::orderConsecutiveCells1D() const
10129 {
10130   checkFullyDefined();
10131   if(getMeshDimension()!=1)
10132     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D works on unstructured mesh with meshdim = 1 !");
10133
10134   // Check that this is a line (and not a more complex 1D mesh) - each point is used at most by 2 segments:
10135   MCAuto<DataArrayInt> _d(DataArrayInt::New()),_dI(DataArrayInt::New());
10136   MCAuto<DataArrayInt> _rD(DataArrayInt::New()),_rDI(DataArrayInt::New());
10137   MCAuto<MEDCouplingUMesh> m_points(buildDescendingConnectivity(_d, _dI, _rD, _rDI));
10138   const int *d(_d->getConstPointer()), *dI(_dI->getConstPointer());
10139   const int *rD(_rD->getConstPointer()), *rDI(_rDI->getConstPointer());
10140   MCAuto<DataArrayInt> _dsi(_rDI->deltaShiftIndex());
10141   const int * dsi(_dsi->getConstPointer());
10142   MCAuto<DataArrayInt> dsii = _dsi->findIdsNotInRange(0,3);
10143   m_points=0;
10144   if (dsii->getNumberOfTuples())
10145     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::orderConsecutiveCells1D only work with a mesh being a (piecewise) connected line!");
10146
10147   int nc(getNumberOfCells());
10148   MCAuto<DataArrayInt> result(DataArrayInt::New());
10149   result->alloc(nc,1);
10150
10151   // set of edges not used so far
10152   std::set<int> edgeSet;
10153   for (int i=0; i<nc; edgeSet.insert(i), i++);
10154
10155   int startSeg=0;
10156   int newIdx=0;
10157   // while we have points with only one neighbor segments
10158   do
10159     {
10160       std::list<int> linePiece;
10161       // fills a list of consecutive segment linked to startSeg. This can go forward or backward.
10162       for (int direction=0;direction<2;direction++) // direction=0 --> forward, direction=1 --> backward
10163         {
10164           // Fill the list forward (resp. backward) from the start segment:
10165           int activeSeg = startSeg;
10166           int prevPointId = -20;
10167           int ptId;
10168           while (!edgeSet.empty())
10169             {
10170               if (!(direction == 1 && prevPointId==-20)) // prevent adding twice startSeg
10171                 {
10172                   if (direction==0)
10173                     linePiece.push_back(activeSeg);
10174                   else
10175                     linePiece.push_front(activeSeg);
10176                   edgeSet.erase(activeSeg);
10177                 }
10178
10179               int ptId1 = d[dI[activeSeg]], ptId2 = d[dI[activeSeg]+1];
10180               ptId = direction ? (ptId1 == prevPointId ? ptId2 : ptId1) : (ptId2 == prevPointId ? ptId1 : ptId2);
10181               if (dsi[ptId] == 1) // hitting the end of the line
10182                 break;
10183               prevPointId = ptId;
10184               int seg1 = rD[rDI[ptId]], seg2 = rD[rDI[ptId]+1];
10185               activeSeg = (seg1 == activeSeg) ? seg2 : seg1;
10186             }
10187         }
10188       // Done, save final piece into DA:
10189       std::copy(linePiece.begin(), linePiece.end(), result->getPointer()+newIdx);
10190       newIdx += linePiece.size();
10191
10192       // identify next valid start segment (one which is not consumed)
10193       if(!edgeSet.empty())
10194         startSeg = *(edgeSet.begin());
10195     }
10196   while (!edgeSet.empty());
10197   return result.retn();
10198 }
10199
10200 /// @cond INTERNAL
10201
10202 void IKGeo2DInternalMapper2(INTERP_KERNEL::Node *n, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10203 {
10204   MCAuto<INTERP_KERNEL::Node> nTmp(n); nTmp->incrRef();
10205   std::map<MCAuto<INTERP_KERNEL::Node>,int>::const_iterator it(m.find(nTmp));
10206   if(it==m.end())
10207     throw INTERP_KERNEL::Exception("Internal error in remapping !");
10208   int v((*it).second);
10209   if(v==forbVal0 || v==forbVal1)
10210     return ;
10211   if(std::find(isect.begin(),isect.end(),v)==isect.end())
10212     isect.push_back(v);
10213 }
10214
10215 bool IKGeo2DInternalMapper(const INTERP_KERNEL::ComposedEdge& c, const std::map<MCAuto<INTERP_KERNEL::Node>,int>& m, int forbVal0, int forbVal1, std::vector<int>& isect)
10216 {
10217   int sz(c.size());
10218   if(sz<=1)
10219     return false;
10220   bool presenceOfOn(false);
10221   for(int i=0;i<sz;i++)
10222     {
10223       INTERP_KERNEL::ElementaryEdge *e(c[i]);
10224       if(e->getLoc()!=INTERP_KERNEL::FULL_ON_1)
10225         continue ;
10226       IKGeo2DInternalMapper2(e->getStartNode(),m,forbVal0,forbVal1,isect);
10227       IKGeo2DInternalMapper2(e->getEndNode(),m,forbVal0,forbVal1,isect);
10228     }
10229   return presenceOfOn;
10230 }
10231
10232 /// @endcond
10233
10234 /**
10235  * This method split some of edges of 2D cells in \a this. The edges to be split are specified in \a subNodesInSeg
10236  * and in \a subNodesInSegI using \ref numbering-indirect storage mode.
10237  * To do the work this method can optionally needs information about middle of subedges for quadratic cases if
10238  * a minimal creation of new nodes is wanted.
10239  * So this method try to reduce at most the number of new nodes. The only case that can lead this method to add
10240  * nodes if a SEG3 is split without information of middle.
10241  * \b WARNING : is returned value is different from 0 a call to MEDCouplingUMesh::mergeNodes is necessary to
10242  * avoid to have a non conform mesh.
10243  *
10244  * \return int - the number of new nodes created (in most of cases 0).
10245  * 
10246  * \throw If \a this is not coherent.
10247  * \throw If \a this has not spaceDim equal to 2.
10248  * \throw If \a this has not meshDim equal to 2.
10249  * \throw If some subcells needed to be split are orphan.
10250  * \sa MEDCouplingUMesh::conformize2D
10251  */
10252 int MEDCouplingUMesh::split2DCells(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *midOpt, const DataArrayInt *midOptI)
10253 {
10254   if(!desc || !descI || !subNodesInSeg || !subNodesInSegI)
10255     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : the 4 first arrays must be not null !");
10256   desc->checkAllocated(); descI->checkAllocated(); subNodesInSeg->checkAllocated(); subNodesInSegI->checkAllocated();
10257   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10258     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10259   if(midOpt==0 && midOptI==0)
10260     {
10261       split2DCellsLinear(desc,descI,subNodesInSeg,subNodesInSegI);
10262       return 0;
10263     }
10264   else if(midOpt!=0 && midOptI!=0)
10265     return split2DCellsQuadratic(desc,descI,subNodesInSeg,subNodesInSegI,midOpt,midOptI);
10266   else
10267     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCells : middle parameters must be set to null for all or not null for all.");
10268 }
10269
10270 /*!
10271  * \b WARNING this method is \b potentially \b non \b const (if returned array is empty).
10272  * \b WARNING this method lead to have a non geometric type sorted mesh (for MED file users) !
10273  * 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
10274  * 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).
10275  * 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.
10276  * 
10277  * Whatever the returned value, this method does not alter the order of cells in \a this neither the orientation of cells.
10278  * The modified cells, if any, are systematically declared as NORM_POLYGON or NORM_QPOLYG depending on the initial quadraticness of geometric type.
10279  *
10280  * This method expects that \b this has a meshDim equal 2 and spaceDim equal to 2 too.
10281  * This method expects that all nodes in \a this are not closer than \a eps.
10282  * If it is not the case you can invoke MEDCouplingUMesh::mergeNodes before calling this method.
10283  * 
10284  * \param [in] eps the relative error to detect merged edges.
10285  * \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
10286  *                           that the user is expected to deal with.
10287  *
10288  * \throw If \a this is not coherent.
10289  * \throw If \a this has not spaceDim equal to 2.
10290  * \throw If \a this has not meshDim equal to 2.
10291  * \sa MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::split2DCells
10292  */
10293 DataArrayInt *MEDCouplingUMesh::conformize2D(double eps)
10294 {
10295   static const int SPACEDIM=2;
10296   checkConsistencyLight();
10297   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10298     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10299   MCAuto<DataArrayInt> desc1(DataArrayInt::New()),descIndx1(DataArrayInt::New()),revDesc1(DataArrayInt::New()),revDescIndx1(DataArrayInt::New());
10300   MCAuto<MEDCouplingUMesh> mDesc(buildDescendingConnectivity(desc1,descIndx1,revDesc1,revDescIndx1));
10301   const int *c(mDesc->getNodalConnectivity()->getConstPointer()),*ci(mDesc->getNodalConnectivityIndex()->getConstPointer()),*rd(revDesc1->getConstPointer()),*rdi(revDescIndx1->getConstPointer());
10302   MCAuto<DataArrayDouble> bboxArr(mDesc->getBoundingBoxForBBTree());
10303   const double *bbox(bboxArr->begin()),*coords(getCoords()->begin());
10304   int nCell(getNumberOfCells()),nDescCell(mDesc->getNumberOfCells());
10305   std::vector< std::vector<int> > intersectEdge(nDescCell),overlapEdge(nDescCell);
10306   std::vector<double> addCoo;
10307   BBTree<SPACEDIM,int> myTree(bbox,0,0,nDescCell,-eps);
10308   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10309   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10310   for(int i=0;i<nDescCell;i++)
10311     {
10312       std::vector<int> candidates;
10313       myTree.getIntersectingElems(bbox+i*2*SPACEDIM,candidates);
10314       for(std::vector<int>::const_iterator it=candidates.begin();it!=candidates.end();it++)
10315         if(*it>i)
10316           {
10317             std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10318             INTERP_KERNEL::Edge *e1(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m)),
10319                 *e2(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[*it]],c+ci[*it]+1,coords,m));
10320             INTERP_KERNEL::MergePoints merge;
10321             INTERP_KERNEL::QuadraticPolygon c1,c2;
10322             e1->intersectWith(e2,merge,c1,c2);
10323             e1->decrRef(); e2->decrRef();
10324             if(IKGeo2DInternalMapper(c1,m,c[ci[i]+1],c[ci[i]+2],intersectEdge[i]))
10325               overlapEdge[i].push_back(*it);
10326             if(IKGeo2DInternalMapper(c2,m,c[ci[*it]+1],c[ci[*it]+2],intersectEdge[*it]))
10327               overlapEdge[*it].push_back(i);
10328           }
10329     }
10330   // splitting done. sort intersect point in intersectEdge.
10331   std::vector< std::vector<int> > middle(nDescCell);
10332   int nbOf2DCellsToBeSplit(0);
10333   bool middleNeedsToBeUsed(false);
10334   std::vector<bool> cells2DToTreat(nDescCell,false);
10335   for(int i=0;i<nDescCell;i++)
10336     {
10337       std::vector<int>& isect(intersectEdge[i]);
10338       int sz((int)isect.size());
10339       if(sz>1)
10340         {
10341           std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
10342           INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2((INTERP_KERNEL::NormalizedCellType)c[ci[i]],c+ci[i]+1,coords,m));
10343           e->sortSubNodesAbs(coords,isect);
10344           e->decrRef();
10345         }
10346       if(sz!=0)
10347         {
10348           int idx0(rdi[i]),idx1(rdi[i+1]);
10349           if(idx1-idx0!=1)
10350             throw INTERP_KERNEL::Exception("MEDCouplingUMesh::conformize2D : internal error #0 !");
10351           if(!cells2DToTreat[rd[idx0]])
10352             {
10353               cells2DToTreat[rd[idx0]]=true;
10354               nbOf2DCellsToBeSplit++;
10355             }
10356           // try to reuse at most eventual 'middle' of SEG3
10357           std::vector<int>& mid(middle[i]);
10358           mid.resize(sz+1,-1);
10359           if((INTERP_KERNEL::NormalizedCellType)c[ci[i]]==INTERP_KERNEL::NORM_SEG3)
10360             {
10361               middleNeedsToBeUsed=true;
10362               const std::vector<int>& candidates(overlapEdge[i]);
10363               std::vector<int> trueCandidates;
10364               for(std::vector<int>::const_iterator itc=candidates.begin();itc!=candidates.end();itc++)
10365                 if((INTERP_KERNEL::NormalizedCellType)c[ci[*itc]]==INTERP_KERNEL::NORM_SEG3)
10366                   trueCandidates.push_back(*itc);
10367               int stNode(c[ci[i]+1]),endNode(isect[0]);
10368               for(int j=0;j<sz+1;j++)
10369                 {
10370                   for(std::vector<int>::const_iterator itc=trueCandidates.begin();itc!=trueCandidates.end();itc++)
10371                     {
10372                       int tmpSt(c[ci[*itc]+1]),tmpEnd(c[ci[*itc]+2]);
10373                       if((tmpSt==stNode && tmpEnd==endNode) || (tmpSt==endNode && tmpEnd==stNode))
10374                         { mid[j]=*itc; break; }
10375                     }
10376                   stNode=endNode;
10377                   endNode=j<sz-1?isect[j+1]:c[ci[i]+2];
10378                 }
10379             }
10380         }
10381     }
10382   MCAuto<DataArrayInt> ret(DataArrayInt::New()),notRet(DataArrayInt::New()); ret->alloc(nbOf2DCellsToBeSplit,1);
10383   if(nbOf2DCellsToBeSplit==0)
10384     return ret.retn();
10385   //
10386   int *retPtr(ret->getPointer());
10387   for(int i=0;i<nCell;i++)
10388     if(cells2DToTreat[i])
10389       *retPtr++=i;
10390   //
10391   MCAuto<DataArrayInt> mSafe,nSafe,oSafe,pSafe,qSafe,rSafe;
10392   DataArrayInt *m(0),*n(0),*o(0),*p(0),*q(0),*r(0);
10393   MEDCouplingUMesh::ExtractFromIndexedArrays(ret->begin(),ret->end(),desc1,descIndx1,m,n); mSafe=m; nSafe=n;
10394   DataArrayInt::PutIntoToSkylineFrmt(intersectEdge,o,p); oSafe=o; pSafe=p;
10395   if(middleNeedsToBeUsed)
10396     { DataArrayInt::PutIntoToSkylineFrmt(middle,q,r); qSafe=q; rSafe=r; }
10397   MCAuto<MEDCouplingUMesh> modif(static_cast<MEDCouplingUMesh *>(buildPartOfMySelf(ret->begin(),ret->end(),true)));
10398   int nbOfNodesCreated(modif->split2DCells(mSafe,nSafe,oSafe,pSafe,qSafe,rSafe));
10399   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.
10400   setPartOfMySelf(ret->begin(),ret->end(),*modif);
10401   {
10402     bool areNodesMerged; int newNbOfNodes;
10403     if(nbOfNodesCreated!=0)
10404       MCAuto<DataArrayInt> tmp(mergeNodes(eps,areNodesMerged,newNbOfNodes));
10405   }
10406   return ret.retn();
10407 }
10408
10409 /*!
10410  * 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.
10411  * 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).
10412  * 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
10413  * to invoke MEDCouplingUMesh::mergeNodes and MEDCouplingUMesh::conformize2D right after this call.
10414  * 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
10415  * new nodes for center of merged edges is are systematically created and appended at the end of the previously existing nodes.
10416  *
10417  * 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
10418  * using new instance, idem for coordinates.
10419  *
10420  * 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.
10421  * 
10422  * \return DataArrayInt  * - The list of cellIds in \a this that have at least one edge colinearized.
10423  *
10424  * \throw If \a this is not coherent.
10425  * \throw If \a this has not spaceDim equal to 2.
10426  * \throw If \a this has not meshDim equal to 2.
10427  * 
10428  * \sa MEDCouplingUMesh::conformize2D, MEDCouplingUMesh::mergeNodes, MEDCouplingUMesh::convexEnvelop2D.
10429  */
10430 DataArrayInt *MEDCouplingUMesh::colinearize2D(double eps)
10431 {
10432   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(0,1);
10433   checkConsistencyLight();
10434   if(getSpaceDimension()!=2 || getMeshDimension()!=2)
10435     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::colinearize2D : This method only works for meshes with spaceDim=2 and meshDim=2 !");
10436   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10437   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10438   int nbOfCells(getNumberOfCells()),nbOfNodes(getNumberOfNodes());
10439   const int *cptr(_nodal_connec->begin()),*ciptr(_nodal_connec_index->begin());
10440   MCAuto<DataArrayInt> newc(DataArrayInt::New()),newci(DataArrayInt::New()); newci->alloc(nbOfCells+1,1); newc->alloc(0,1); newci->setIJ(0,0,0);
10441   MCAuto<DataArrayDouble> appendedCoords(DataArrayDouble::New()); appendedCoords->alloc(0,1);//1 not 2 it is not a bug.
10442   const double *coords(_coords->begin());
10443   int *newciptr(newci->getPointer());
10444   for(int i=0;i<nbOfCells;i++,newciptr++,ciptr++)
10445     {
10446       if(Colinearize2DCell(coords,cptr+ciptr[0],cptr+ciptr[1],nbOfNodes,newc,appendedCoords))
10447         ret->pushBackSilent(i);
10448       newciptr[1]=newc->getNumberOfTuples();
10449     }
10450   //
10451   if(ret->empty())
10452     return ret.retn();
10453   if(!appendedCoords->empty())
10454     {
10455       appendedCoords->rearrange(2);
10456       MCAuto<DataArrayDouble> newCoords(DataArrayDouble::Aggregate(getCoords(),appendedCoords));//treat info on components
10457       //non const part
10458       setCoords(newCoords);
10459     }
10460   //non const part
10461   setConnectivity(newc,newci,true);
10462   return ret.retn();
10463 }
10464
10465 /*!
10466  * \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.
10467  *                               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.
10468  *                               And for each j in [1,n) intersect[i][2*(j-1)+1]==intersect[i][2*j].
10469  * \param [out] subDiv2 - for each cell in \a m2Desc returns nodes that split it using convention \a m1Desc first, then \a m2Desc, then addCoo
10470  * \param [out] colinear2 - for each cell in \a m2Desc returns the edges in \a m1Desc that are colinear to it.
10471  * \param [out] addCoo - nodes to be append at the end
10472  * \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.
10473  */
10474 void MEDCouplingUMesh::Intersect1DMeshes(const MEDCouplingUMesh *m1Desc, const MEDCouplingUMesh *m2Desc, double eps,
10475                                          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)
10476 {
10477   static const int SPACEDIM=2;
10478   INTERP_KERNEL::QUADRATIC_PLANAR::_precision=eps;
10479   INTERP_KERNEL::QUADRATIC_PLANAR::_arc_detection_precision=eps;
10480   const int *c1(m1Desc->getNodalConnectivity()->getConstPointer()),*ci1(m1Desc->getNodalConnectivityIndex()->getConstPointer());
10481   // Build BB tree of all edges in the tool mesh (second mesh)
10482   MCAuto<DataArrayDouble> bbox1Arr(m1Desc->getBoundingBoxForBBTree()),bbox2Arr(m2Desc->getBoundingBoxForBBTree());
10483   const double *bbox1(bbox1Arr->begin()),*bbox2(bbox2Arr->begin());
10484   int nDescCell1(m1Desc->getNumberOfCells()),nDescCell2(m2Desc->getNumberOfCells());
10485   intersectEdge1.resize(nDescCell1);
10486   colinear2.resize(nDescCell2);
10487   subDiv2.resize(nDescCell2);
10488   BBTree<SPACEDIM,int> myTree(bbox2,0,0,m2Desc->getNumberOfCells(),-eps);
10489
10490   std::vector<int> candidates1(1);
10491   int offset1(m1Desc->getNumberOfNodes());
10492   int offset2(offset1+m2Desc->getNumberOfNodes());
10493   for(int i=0;i<nDescCell1;i++)  // for all edges in the first mesh
10494     {
10495       std::vector<int> candidates2; // edges of mesh2 candidate for intersection
10496       myTree.getIntersectingElems(bbox1+i*2*SPACEDIM,candidates2);
10497       if(!candidates2.empty()) // candidates2 holds edges from the second mesh potentially intersecting current edge i in mesh1
10498         {
10499           std::map<INTERP_KERNEL::Node *,int> map1,map2;
10500           // pol2 is not necessarily a closed polygon: just a set of (quadratic) edges (same as candidates2) in the Geometric DS format
10501           INTERP_KERNEL::QuadraticPolygon *pol2=MEDCouplingUMeshBuildQPFromMesh(m2Desc,candidates2,map2);
10502           candidates1[0]=i;
10503           INTERP_KERNEL::QuadraticPolygon *pol1=MEDCouplingUMeshBuildQPFromMesh(m1Desc,candidates1,map1);
10504           // 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
10505           // This trick guarantees that Node * are discriminant (i.e. form a unique identifier)
10506           std::set<INTERP_KERNEL::Node *> nodes;
10507           pol1->getAllNodes(nodes); pol2->getAllNodes(nodes);
10508           std::size_t szz(nodes.size());
10509           std::vector< MCAuto<INTERP_KERNEL::Node> > nodesSafe(szz);
10510           std::set<INTERP_KERNEL::Node *>::const_iterator itt(nodes.begin());
10511           for(std::size_t iii=0;iii<szz;iii++,itt++)
10512             { (*itt)->incrRef(); nodesSafe[iii]=*itt; }
10513           // end of protection
10514           // Performs egde cutting:
10515           pol1->splitAbs(*pol2,map1,map2,offset1,offset2,candidates2,intersectEdge1[i],i,colinear2,subDiv2,addCoo,mergedNodes);
10516           delete pol2;
10517           delete pol1;
10518         }
10519       else
10520         // Copy the edge (take only the two first points, ie discard quadratic point at this stage)
10521         intersectEdge1[i].insert(intersectEdge1[i].end(),c1+ci1[i]+1,c1+ci1[i]+3);
10522     }
10523 }
10524
10525 /*!
10526  * This method is private and is the first step of Partition of 2D mesh (spaceDim==2 and meshDim==2).
10527  * It builds the descending connectivity of the two meshes, and then using a binary tree
10528  * it computes the edge intersections. This results in new points being created : they're stored in addCoo.
10529  * Documentation about parameters  colinear2 and subDiv2 can be found in method QuadraticPolygon::splitAbs().
10530  */
10531 void MEDCouplingUMesh::IntersectDescending2DMeshes(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2, double eps,
10532                                                    std::vector< std::vector<int> >& intersectEdge1, std::vector< std::vector<int> >& colinear2, std::vector< std::vector<int> >& subDiv2,
10533                                                    MEDCouplingUMesh *& m1Desc, DataArrayInt *&desc1, DataArrayInt *&descIndx1, DataArrayInt *&revDesc1, DataArrayInt *&revDescIndx1,
10534                                                    std::vector<double>& addCoo,
10535                                                    MEDCouplingUMesh *& m2Desc, DataArrayInt *&desc2, DataArrayInt *&descIndx2, DataArrayInt *&revDesc2, DataArrayInt *&revDescIndx2)
10536 {
10537   // Build desc connectivity
10538   desc1=DataArrayInt::New(); descIndx1=DataArrayInt::New(); revDesc1=DataArrayInt::New(); revDescIndx1=DataArrayInt::New();
10539   desc2=DataArrayInt::New();
10540   descIndx2=DataArrayInt::New();
10541   revDesc2=DataArrayInt::New();
10542   revDescIndx2=DataArrayInt::New();
10543   MCAuto<DataArrayInt> dd1(desc1),dd2(descIndx1),dd3(revDesc1),dd4(revDescIndx1);
10544   MCAuto<DataArrayInt> dd5(desc2),dd6(descIndx2),dd7(revDesc2),dd8(revDescIndx2);
10545   m1Desc=m1->buildDescendingConnectivity2(desc1,descIndx1,revDesc1,revDescIndx1);
10546   m2Desc=m2->buildDescendingConnectivity2(desc2,descIndx2,revDesc2,revDescIndx2);
10547   MCAuto<MEDCouplingUMesh> dd9(m1Desc),dd10(m2Desc);
10548   std::map<int,int> notUsedMap;
10549   Intersect1DMeshes(m1Desc,m2Desc,eps,intersectEdge1,colinear2,subDiv2,addCoo,notUsedMap);
10550   m1Desc->incrRef(); desc1->incrRef(); descIndx1->incrRef(); revDesc1->incrRef(); revDescIndx1->incrRef();
10551   m2Desc->incrRef(); desc2->incrRef(); descIndx2->incrRef(); revDesc2->incrRef(); revDescIndx2->incrRef();
10552 }
10553
10554 /*!
10555  * This method performs the 2nd step of Partition of 2D mesh.
10556  * This method has 4 inputs :
10557  *  - a mesh 'm1' with meshDim==1 and a SpaceDim==2
10558  *  - a mesh 'm2' with meshDim==1 and a SpaceDim==2
10559  *  - subDiv of size 'm2->getNumberOfCells()' that lists for each seg cell in 'm' the splitting node ids randomly sorted.
10560  * 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'
10561  * Nodes end up lying consecutively on a cutted edge.
10562  * \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.
10563  * (Only present for its coords in case of 'subDiv' shares some nodes of 'm1')
10564  * \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.
10565  * \param addCoo input parameter with additional nodes linked to intersection of the 2 meshes.
10566  * \param[out] intersectEdge the same content as subDiv, but correclty oriented.
10567  */
10568 void MEDCouplingUMesh::BuildIntersectEdges(const MEDCouplingUMesh *m1, const MEDCouplingUMesh *m2,
10569                                            const std::vector<double>& addCoo,
10570                                            const std::vector< std::vector<int> >& subDiv, std::vector< std::vector<int> >& intersectEdge)
10571 {
10572   int offset1=m1->getNumberOfNodes();
10573   int ncell=m2->getNumberOfCells();
10574   const int *c=m2->getNodalConnectivity()->getConstPointer();
10575   const int *cI=m2->getNodalConnectivityIndex()->getConstPointer();
10576   const double *coo=m2->getCoords()->getConstPointer();
10577   const double *cooBis=m1->getCoords()->getConstPointer();
10578   int offset2=offset1+m2->getNumberOfNodes();
10579   intersectEdge.resize(ncell);
10580   for(int i=0;i<ncell;i++,cI++)
10581     {
10582       const std::vector<int>& divs=subDiv[i];
10583       int nnode=cI[1]-cI[0]-1;
10584       std::map<int, std::pair<INTERP_KERNEL::Node *,bool> > mapp2;
10585       std::map<INTERP_KERNEL::Node *, int> mapp22;
10586       for(int j=0;j<nnode;j++)
10587         {
10588           INTERP_KERNEL::Node *nn=new INTERP_KERNEL::Node(coo[2*c[(*cI)+j+1]],coo[2*c[(*cI)+j+1]+1]);
10589           int nnid=c[(*cI)+j+1];
10590           mapp2[nnid]=std::pair<INTERP_KERNEL::Node *,bool>(nn,true);
10591           mapp22[nn]=nnid+offset1;
10592         }
10593       INTERP_KERNEL::Edge *e=MEDCouplingUMeshBuildQPFromEdge((INTERP_KERNEL::NormalizedCellType)c[*cI],mapp2,c+(*cI)+1);
10594       for(std::map<int, std::pair<INTERP_KERNEL::Node *,bool> >::const_iterator it=mapp2.begin();it!=mapp2.end();it++)
10595         ((*it).second.first)->decrRef();
10596       std::vector<INTERP_KERNEL::Node *> addNodes(divs.size());
10597       std::map<INTERP_KERNEL::Node *,int> mapp3;
10598       for(std::size_t j=0;j<divs.size();j++)
10599         {
10600           int id=divs[j];
10601           INTERP_KERNEL::Node *tmp=0;
10602           if(id<offset1)
10603             tmp=new INTERP_KERNEL::Node(cooBis[2*id],cooBis[2*id+1]);
10604           else if(id<offset2)
10605             tmp=new INTERP_KERNEL::Node(coo[2*(id-offset1)],coo[2*(id-offset1)+1]);//if it happens, bad news mesh 'm2' is non conform.
10606           else
10607             tmp=new INTERP_KERNEL::Node(addCoo[2*(id-offset2)],addCoo[2*(id-offset2)+1]);
10608           addNodes[j]=tmp;
10609           mapp3[tmp]=id;
10610         }
10611       e->sortIdsAbs(addNodes,mapp22,mapp3,intersectEdge[i]);
10612       for(std::vector<INTERP_KERNEL::Node *>::const_iterator it=addNodes.begin();it!=addNodes.end();it++)
10613         (*it)->decrRef();
10614       e->decrRef();
10615     }
10616 }
10617
10618 /*!
10619  * 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).
10620  * 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
10621  * with a plane. The result will be put in 'cut3DSuf' out parameter.
10622  * \param [in] cut3DCurve  input paramter that gives for each 3DCurve cell if it owns fully to the plane or partially.
10623  * \param [out] nodesOnPlane, returns all the nodes that are on the plane.
10624  * \param [in] nodal3DSurf is the nodal connectivity of 3D surf mesh.
10625  * \param [in] nodalIndx3DSurf is the nodal connectivity index of 3D surf mesh.
10626  * \param [in] nodal3DCurve is the nodal connectivity of 3D curve mesh.
10627  * \param [in] nodal3DIndxCurve is the nodal connectivity index of 3D curve mesh.
10628  * \param [in] desc is the descending connectivity 3DSurf->3DCurve
10629  * \param [in] descIndx is the descending connectivity index 3DSurf->3DCurve
10630  * \param [out] cut3DSuf input/output param.
10631  */
10632 void MEDCouplingUMesh::AssemblyForSplitFrom3DCurve(const std::vector<int>& cut3DCurve, std::vector<int>& nodesOnPlane, const int *nodal3DSurf, const int *nodalIndx3DSurf,
10633                                                    const int *nodal3DCurve, const int *nodalIndx3DCurve,
10634                                                    const int *desc, const int *descIndx, 
10635                                                    std::vector< std::pair<int,int> >& cut3DSurf)
10636 {
10637   std::set<int> nodesOnP(nodesOnPlane.begin(),nodesOnPlane.end());
10638   int nbOf3DSurfCell=(int)cut3DSurf.size();
10639   for(int i=0;i<nbOf3DSurfCell;i++)
10640     {
10641       std::vector<int> res;
10642       int offset=descIndx[i];
10643       int nbOfSeg=descIndx[i+1]-offset;
10644       for(int j=0;j<nbOfSeg;j++)
10645         {
10646           int edgeId=desc[offset+j];
10647           int status=cut3DCurve[edgeId];
10648           if(status!=-2)
10649             {
10650               if(status>-1)
10651                 res.push_back(status);
10652               else
10653                 {
10654                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+1]);
10655                   res.push_back(nodal3DCurve[nodalIndx3DCurve[edgeId]+2]);
10656                 }
10657             }
10658         }
10659       switch(res.size())
10660       {
10661         case 2:
10662           {
10663             cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10664             break;
10665           }
10666         case 1:
10667         case 0:
10668           {
10669             std::set<int> s1(nodal3DSurf+nodalIndx3DSurf[i]+1,nodal3DSurf+nodalIndx3DSurf[i+1]);
10670             std::set_intersection(nodesOnP.begin(),nodesOnP.end(),s1.begin(),s1.end(),std::back_insert_iterator< std::vector<int> >(res));
10671             if(res.size()==2)
10672               {
10673                 cut3DSurf[i].first=res[0]; cut3DSurf[i].second=res[1];
10674               }
10675             else
10676               {
10677                 cut3DSurf[i].first=-1; cut3DSurf[i].second=-1;
10678               }
10679             break;
10680           }
10681         default:
10682           {// case when plane is on a multi colinear edge of a polyhedron
10683             if((int)res.size()==2*nbOfSeg)
10684               {
10685                 cut3DSurf[i].first=-2; cut3DSurf[i].second=i;
10686               }
10687             else
10688               throw INTERP_KERNEL::Exception("MEDCouplingUMesh::AssemblyPointsFrom3DCurve : unexpected situation !");
10689           }
10690       }
10691     }
10692 }
10693
10694 /*!
10695  * \a this is expected to be a mesh with spaceDim==3 and meshDim==3. If not an exception will be thrown.
10696  * 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).
10697  * 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
10698  * with a plane. The result will be put in 'nodalRes' 'nodalResIndx' and 'cellIds' out parameters.
10699  * \param cut3DSurf  input paramter that gives for each 3DSurf its intersection with plane (result of MEDCouplingUMesh::AssemblyForSplitFrom3DCurve).
10700  * \param desc is the descending connectivity 3D->3DSurf
10701  * \param descIndx is the descending connectivity index 3D->3DSurf
10702  */
10703 void MEDCouplingUMesh::assemblyForSplitFrom3DSurf(const std::vector< std::pair<int,int> >& cut3DSurf,
10704                                                   const int *desc, const int *descIndx,
10705                                                   DataArrayInt *nodalRes, DataArrayInt *nodalResIndx, DataArrayInt *cellIds) const
10706 {
10707   checkFullyDefined();
10708   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
10709     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::assemblyForSplitFrom3DSurf works on umeshes with meshdim equal to 3 and spaceDim equal to 3 too!");
10710   const int *nodal3D=_nodal_connec->getConstPointer();
10711   const int *nodalIndx3D=_nodal_connec_index->getConstPointer();
10712   int nbOfCells=getNumberOfCells();
10713   for(int i=0;i<nbOfCells;i++)
10714     {
10715       std::map<int, std::set<int> > m;
10716       int offset=descIndx[i];
10717       int nbOfFaces=descIndx[i+1]-offset;
10718       int start=-1;
10719       int end=-1;
10720       for(int j=0;j<nbOfFaces;j++)
10721         {
10722           const std::pair<int,int>& p=cut3DSurf[desc[offset+j]];
10723           if(p.first!=-1 && p.second!=-1)
10724             {
10725               if(p.first!=-2)
10726                 {
10727                   start=p.first; end=p.second;
10728                   m[p.first].insert(p.second);
10729                   m[p.second].insert(p.first);
10730                 }
10731               else
10732                 {
10733                   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)nodal3D[nodalIndx3D[i]]);
10734                   int sz=nodalIndx3D[i+1]-nodalIndx3D[i]-1;
10735                   INTERP_KERNEL::AutoPtr<int> tmp=new int[sz];
10736                   INTERP_KERNEL::NormalizedCellType cmsId;
10737                   unsigned nbOfNodesSon=cm.fillSonCellNodalConnectivity2(j,nodal3D+nodalIndx3D[i]+1,sz,tmp,cmsId);
10738                   start=tmp[0]; end=tmp[nbOfNodesSon-1];
10739                   for(unsigned k=0;k<nbOfNodesSon;k++)
10740                     {
10741                       m[tmp[k]].insert(tmp[(k+1)%nbOfNodesSon]);
10742                       m[tmp[(k+1)%nbOfNodesSon]].insert(tmp[k]);
10743                     }
10744                 }
10745             }
10746         }
10747       if(m.empty())
10748         continue;
10749       std::vector<int> conn(1,(int)INTERP_KERNEL::NORM_POLYGON);
10750       int prev=end;
10751       while(end!=start)
10752         {
10753           std::map<int, std::set<int> >::const_iterator it=m.find(start);
10754           const std::set<int>& s=(*it).second;
10755           std::set<int> s2; s2.insert(prev);
10756           std::set<int> s3;
10757           std::set_difference(s.begin(),s.end(),s2.begin(),s2.end(),inserter(s3,s3.begin()));
10758           if(s3.size()==1)
10759             {
10760               int val=*s3.begin();
10761               conn.push_back(start);
10762               prev=start;
10763               start=val;
10764             }
10765           else
10766             start=end;
10767         }
10768       conn.push_back(end);
10769       if(conn.size()>3)
10770         {
10771           nodalRes->insertAtTheEnd(conn.begin(),conn.end());
10772           nodalResIndx->pushBackSilent(nodalRes->getNumberOfTuples());
10773           cellIds->pushBackSilent(i);
10774         }
10775     }
10776 }
10777
10778 /*!
10779  * 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
10780  * 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
10781  * the geometric cell type set to INTERP_KERNEL::NORM_POLYGON.
10782  * 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
10783  * 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.
10784  * 
10785  * \return false if the input connectivity represents already the convex hull, true if the input cell needs to be reordered.
10786  */
10787 bool MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis(const double *coords, const int *nodalConnBg, const int *nodalConnEnd, DataArrayInt *nodalConnecOut)
10788 {
10789   std::size_t sz=std::distance(nodalConnBg,nodalConnEnd);
10790   if(sz>=4)
10791     {
10792       const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)*nodalConnBg);
10793       if(cm.getDimension()==2)
10794         {
10795           const int *node=nodalConnBg+1;
10796           int startNode=*node++;
10797           double refX=coords[2*startNode];
10798           for(;node!=nodalConnEnd;node++)
10799             {
10800               if(coords[2*(*node)]<refX)
10801                 {
10802                   startNode=*node;
10803                   refX=coords[2*startNode];
10804                 }
10805             }
10806           std::vector<int> tmpOut; tmpOut.reserve(sz); tmpOut.push_back(startNode);
10807           refX=1e300;
10808           double tmp1;
10809           double tmp2[2];
10810           double angle0=-M_PI/2;
10811           //
10812           int nextNode=-1;
10813           int prevNode=-1;
10814           double resRef;
10815           double angleNext=0.;
10816           while(nextNode!=startNode)
10817             {
10818               nextNode=-1;
10819               resRef=1e300;
10820               for(node=nodalConnBg+1;node!=nodalConnEnd;node++)
10821                 {
10822                   if(*node!=tmpOut.back() && *node!=prevNode)
10823                     {
10824                       tmp2[0]=coords[2*(*node)]-coords[2*tmpOut.back()]; tmp2[1]=coords[2*(*node)+1]-coords[2*tmpOut.back()+1];
10825                       double angleM=INTERP_KERNEL::EdgeArcCircle::GetAbsoluteAngle(tmp2,tmp1);
10826                       double res;
10827                       if(angleM<=angle0)
10828                         res=angle0-angleM;
10829                       else
10830                         res=angle0-angleM+2.*M_PI;
10831                       if(res<resRef)
10832                         {
10833                           nextNode=*node;
10834                           resRef=res;
10835                           angleNext=angleM;
10836                         }
10837                     }
10838                 }
10839               if(nextNode!=startNode)
10840                 {
10841                   angle0=angleNext-M_PI;
10842                   if(angle0<-M_PI)
10843                     angle0+=2*M_PI;
10844                   prevNode=tmpOut.back();
10845                   tmpOut.push_back(nextNode);
10846                 }
10847             }
10848           std::vector<int> tmp3(2*(sz-1));
10849           std::vector<int>::iterator it=std::copy(nodalConnBg+1,nodalConnEnd,tmp3.begin());
10850           std::copy(nodalConnBg+1,nodalConnEnd,it);
10851           if(std::search(tmp3.begin(),tmp3.end(),tmpOut.begin(),tmpOut.end())!=tmp3.end())
10852             {
10853               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10854               return false;
10855             }
10856           if(std::search(tmp3.rbegin(),tmp3.rend(),tmpOut.begin(),tmpOut.end())!=tmp3.rend())
10857             {
10858               nodalConnecOut->insertAtTheEnd(nodalConnBg,nodalConnEnd);
10859               return false;
10860             }
10861           else
10862             {
10863               nodalConnecOut->pushBackSilent((int)INTERP_KERNEL::NORM_POLYGON);
10864               nodalConnecOut->insertAtTheEnd(tmpOut.begin(),tmpOut.end());
10865               return true;
10866             }
10867         }
10868       else
10869         throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10870     }
10871   else
10872     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::BuildConvexEnvelopOf2DCellJarvis : invalid 2D cell connectivity !");
10873 }
10874
10875 /*!
10876  * This method works on an input pair (\b arr, \b arrIndx) where \b arr indexes is in \b arrIndx.
10877  * 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.
10878  * 
10879  * \param [in] idsToRemoveBg begin of set of ids to remove in \b arr (included)
10880  * \param [in] idsToRemoveEnd end of set of ids to remove in \b arr (excluded)
10881  * \param [in,out] arr array in which the remove operation will be done.
10882  * \param [in,out] arrIndx array in the remove operation will modify
10883  * \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])
10884  * \return true if \b arr and \b arrIndx have been modified, false if not.
10885  */
10886 bool MEDCouplingUMesh::RemoveIdsFromIndexedArrays(const int *idsToRemoveBg, const int *idsToRemoveEnd, DataArrayInt *arr, DataArrayInt *arrIndx, int offsetForRemoval)
10887 {
10888   if(!arrIndx || !arr)
10889     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : some input arrays are empty !");
10890   if(offsetForRemoval<0)
10891     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::RemoveIdsFromIndexedArrays : offsetForRemoval should be >=0 !");
10892   std::set<int> s(idsToRemoveBg,idsToRemoveEnd);
10893   int nbOfGrps=arrIndx->getNumberOfTuples()-1;
10894   int *arrIPtr=arrIndx->getPointer();
10895   *arrIPtr++=0;
10896   int previousArrI=0;
10897   const int *arrPtr=arr->getConstPointer();
10898   std::vector<int> arrOut;//no utility to switch to DataArrayInt because copy always needed
10899   for(int i=0;i<nbOfGrps;i++,arrIPtr++)
10900     {
10901       if(*arrIPtr-previousArrI>offsetForRemoval)
10902         {
10903           for(const int *work=arrPtr+previousArrI+offsetForRemoval;work!=arrPtr+*arrIPtr;work++)
10904             {
10905               if(s.find(*work)==s.end())
10906                 arrOut.push_back(*work);
10907             }
10908         }
10909       previousArrI=*arrIPtr;
10910       *arrIPtr=(int)arrOut.size();
10911     }
10912   if(arr->getNumberOfTuples()==(int)arrOut.size())
10913     return false;
10914   arr->alloc((int)arrOut.size(),1);
10915   std::copy(arrOut.begin(),arrOut.end(),arr->getPointer());
10916   return true;
10917 }
10918
10919 /*!
10920  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10921  * (\ref numbering-indirect).
10922  * This method returns the result of the extraction ( specified by a set of ids in [\b idsOfSelectBg , \b idsOfSelectEnd ) ).
10923  * The selection of extraction is done standardly in new2old format.
10924  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10925  *
10926  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
10927  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
10928  * \param [in] arrIn arr origin array from which the extraction will be done.
10929  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
10930  * \param [out] arrOut the resulting array
10931  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
10932  * \sa MEDCouplingUMesh::ExtractFromIndexedArraysSlice
10933  */
10934 void MEDCouplingUMesh::ExtractFromIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
10935                                                 DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
10936 {
10937   if(!arrIn || !arrIndxIn)
10938     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input pointer is NULL !");
10939   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
10940   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
10941     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : input arrays must have exactly one component !");
10942   std::size_t sz=std::distance(idsOfSelectBg,idsOfSelectEnd);
10943   const int *arrInPtr=arrIn->getConstPointer();
10944   const int *arrIndxPtr=arrIndxIn->getConstPointer();
10945   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
10946   if(nbOfGrps<0)
10947     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArrays : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
10948   int maxSizeOfArr=arrIn->getNumberOfTuples();
10949   MCAuto<DataArrayInt> arro=DataArrayInt::New();
10950   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
10951   arrIo->alloc((int)(sz+1),1);
10952   const int *idsIt=idsOfSelectBg;
10953   int *work=arrIo->getPointer();
10954   *work++=0;
10955   int lgth=0;
10956   for(std::size_t i=0;i<sz;i++,work++,idsIt++)
10957     {
10958       if(*idsIt>=0 && *idsIt<nbOfGrps)
10959         lgth+=arrIndxPtr[*idsIt+1]-arrIndxPtr[*idsIt];
10960       else
10961         {
10962           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " ! Must be in [0," << nbOfGrps << ") !";
10963           throw INTERP_KERNEL::Exception(oss.str().c_str());
10964         }
10965       if(lgth>=work[-1])
10966         *work=lgth;
10967       else
10968         {
10969           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " and at this pos arrIndxIn[" << *idsIt;
10970           oss << "+1]-arrIndxIn[" << *idsIt << "] < 0 ! The input index array is bugged !";
10971           throw INTERP_KERNEL::Exception(oss.str().c_str());
10972         }
10973     }
10974   arro->alloc(lgth,1);
10975   work=arro->getPointer();
10976   idsIt=idsOfSelectBg;
10977   for(std::size_t i=0;i<sz;i++,idsIt++)
10978     {
10979       if(arrIndxPtr[*idsIt]>=0 && arrIndxPtr[*idsIt+1]<=maxSizeOfArr)
10980         work=std::copy(arrInPtr+arrIndxPtr[*idsIt],arrInPtr+arrIndxPtr[*idsIt+1],work);
10981       else
10982         {
10983           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArrays : id located on pos #" << i << " value is " << *idsIt << " arrIndx[" << *idsIt << "] must be >= 0 and arrIndx[";
10984           oss << *idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
10985           throw INTERP_KERNEL::Exception(oss.str().c_str());
10986         }
10987     }
10988   arrOut=arro.retn();
10989   arrIndexOut=arrIo.retn();
10990 }
10991
10992 /*!
10993  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn
10994  * (\ref numbering-indirect).
10995  * 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 ).
10996  * The selection of extraction is done standardly in new2old format.
10997  * This method returns indexed arrays (\ref numbering-indirect) using 2 arrays (arrOut,arrIndexOut).
10998  *
10999  * \param [in] idsOfSelectStart begin of set of ids of the input extraction (included)
11000  * \param [in] idsOfSelectStop end of set of ids of the input extraction (excluded)
11001  * \param [in] idsOfSelectStep
11002  * \param [in] arrIn arr origin array from which the extraction will be done.
11003  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11004  * \param [out] arrOut the resulting array
11005  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11006  * \sa MEDCouplingUMesh::ExtractFromIndexedArrays
11007  */
11008 void MEDCouplingUMesh::ExtractFromIndexedArraysSlice(int idsOfSelectStart, int idsOfSelectStop, int idsOfSelectStep, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11009                                                  DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11010 {
11011   if(!arrIn || !arrIndxIn)
11012     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input pointer is NULL !");
11013   arrIn->checkAllocated(); arrIndxIn->checkAllocated();
11014   if(arrIn->getNumberOfComponents()!=1 || arrIndxIn->getNumberOfComponents()!=1)
11015     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : input arrays must have exactly one component !");
11016   int sz=DataArrayInt::GetNumberOfItemGivenBESRelative(idsOfSelectStart,idsOfSelectStop,idsOfSelectStep,"MEDCouplingUMesh::ExtractFromIndexedArraysSlice : Input slice ");
11017   const int *arrInPtr=arrIn->getConstPointer();
11018   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11019   int nbOfGrps=arrIndxIn->getNumberOfTuples()-1;
11020   if(nbOfGrps<0)
11021     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ExtractFromIndexedArraysSlice : The format of \"arrIndxIn\" is invalid ! Its nb of tuples should be >=1 !");
11022   int maxSizeOfArr=arrIn->getNumberOfTuples();
11023   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11024   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11025   arrIo->alloc((int)(sz+1),1);
11026   int idsIt=idsOfSelectStart;
11027   int *work=arrIo->getPointer();
11028   *work++=0;
11029   int lgth=0;
11030   for(int i=0;i<sz;i++,work++,idsIt+=idsOfSelectStep)
11031     {
11032       if(idsIt>=0 && idsIt<nbOfGrps)
11033         lgth+=arrIndxPtr[idsIt+1]-arrIndxPtr[idsIt];
11034       else
11035         {
11036           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " ! Must be in [0," << nbOfGrps << ") !";
11037           throw INTERP_KERNEL::Exception(oss.str().c_str());
11038         }
11039       if(lgth>=work[-1])
11040         *work=lgth;
11041       else
11042         {
11043           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " and at this pos arrIndxIn[" << idsIt;
11044           oss << "+1]-arrIndxIn[" << idsIt << "] < 0 ! The input index array is bugged !";
11045           throw INTERP_KERNEL::Exception(oss.str().c_str());
11046         }
11047     }
11048   arro->alloc(lgth,1);
11049   work=arro->getPointer();
11050   idsIt=idsOfSelectStart;
11051   for(int i=0;i<sz;i++,idsIt+=idsOfSelectStep)
11052     {
11053       if(arrIndxPtr[idsIt]>=0 && arrIndxPtr[idsIt+1]<=maxSizeOfArr)
11054         work=std::copy(arrInPtr+arrIndxPtr[idsIt],arrInPtr+arrIndxPtr[idsIt+1],work);
11055       else
11056         {
11057           std::ostringstream oss; oss << "MEDCouplingUMesh::ExtractFromIndexedArraysSlice : id located on pos #" << i << " value is " << idsIt << " arrIndx[" << idsIt << "] must be >= 0 and arrIndx[";
11058           oss << idsIt << "+1] <= " << maxSizeOfArr << " (the size of arrIn)!";
11059           throw INTERP_KERNEL::Exception(oss.str().c_str());
11060         }
11061     }
11062   arrOut=arro.retn();
11063   arrIndexOut=arrIo.retn();
11064 }
11065
11066 /*!
11067  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11068  * 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
11069  * cellIds \b in [ \b idsOfSelectBg , \b idsOfSelectEnd ) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11070  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11071  *
11072  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11073  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11074  * \param [in] arrIn arr origin array from which the extraction will be done.
11075  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11076  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg, \b idsOfSelectEnd )
11077  * \param [in] srcArrIndex index array of \b srcArr
11078  * \param [out] arrOut the resulting array
11079  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11080  * 
11081  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11082  */
11083 void MEDCouplingUMesh::SetPartOfIndexedArrays(const int *idsOfSelectBg, const int *idsOfSelectEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11084                                               const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11085                                               DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11086 {
11087   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11088     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArrays : presence of null pointer in input parameter !");
11089   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11090   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11091   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11092   std::vector<bool> v(nbOfTuples,true);
11093   int offset=0;
11094   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11095   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11096   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11097     {
11098       if(*it>=0 && *it<nbOfTuples)
11099         {
11100           v[*it]=false;
11101           offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[*it+1]-arrIndxInPtr[*it]);
11102         }
11103       else
11104         {
11105           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArrays : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11106           throw INTERP_KERNEL::Exception(oss.str().c_str());
11107         }
11108     }
11109   srcArrIndexPtr=srcArrIndex->getConstPointer();
11110   arrIo->alloc(nbOfTuples+1,1);
11111   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11112   const int *arrInPtr=arrIn->getConstPointer();
11113   const int *srcArrPtr=srcArr->getConstPointer();
11114   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11115   int *arroPtr=arro->getPointer();
11116   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11117     {
11118       if(v[ii])
11119         {
11120           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11121           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11122         }
11123       else
11124         {
11125           std::size_t pos=std::distance(idsOfSelectBg,std::find(idsOfSelectBg,idsOfSelectEnd,ii));
11126           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11127           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11128         }
11129     }
11130   arrOut=arro.retn();
11131   arrIndexOut=arrIo.retn();
11132 }
11133
11134 /*!
11135  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11136  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11137  *
11138  * \param [in] idsOfSelectBg begin of set of ids of the input extraction (included)
11139  * \param [in] idsOfSelectEnd end of set of ids of the input extraction (excluded)
11140  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11141  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11142  * \param [in] srcArr input array that will be used as source of copy for ids in [ \b idsOfSelectBg , \b idsOfSelectEnd )
11143  * \param [in] srcArrIndex index array of \b srcArr
11144  * 
11145  * \sa MEDCouplingUMesh::SetPartOfIndexedArrays
11146  */
11147 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx(const int *idsOfSelectBg, const int *idsOfSelectEnd, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11148                                                      const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11149 {
11150   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11151     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : presence of null pointer in input parameter !");
11152   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11153   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11154   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11155   int *arrInOutPtr=arrInOut->getPointer();
11156   const int *srcArrPtr=srcArr->getConstPointer();
11157   for(const int *it=idsOfSelectBg;it!=idsOfSelectEnd;it++,srcArrIndexPtr++)
11158     {
11159       if(*it>=0 && *it<nbOfTuples)
11160         {
11161           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[*it+1]-arrIndxInPtr[*it])
11162             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[*it]);
11163           else
11164             {
11165               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] !";
11166               throw INTERP_KERNEL::Exception(oss.str().c_str());
11167             }
11168         }
11169       else
11170         {
11171           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx : On pos #" << std::distance(idsOfSelectBg,it) << " value is " << *it << " not in [0," << nbOfTuples << ") !";
11172           throw INTERP_KERNEL::Exception(oss.str().c_str());
11173         }
11174     }
11175 }
11176
11177 /*!
11178  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11179  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11180  * 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]].
11181  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11182  * A negative value in \b arrIn means that it is ignored.
11183  * 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.
11184  * 
11185  * \param [in] arrIn arr origin array from which the extraction will be done.
11186  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11187  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11188  * \sa MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed, MEDCouplingUMesh::partitionBySpreadZone
11189  */
11190 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGradually(const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn)
11191 {
11192   int seed=0,nbOfDepthPeelingPerformed=0;
11193   return ComputeSpreadZoneGraduallyFromSeed(&seed,&seed+1,arrIn,arrIndxIn,-1,nbOfDepthPeelingPerformed);
11194 }
11195
11196 /*!
11197  * This method works on a pair input (\b arrIn, \b arrIndxIn) where \b arr indexes is in \b arrIndxIn.
11198  * This method expects that these two input arrays come from the output of MEDCouplingUMesh::computeNeighborsOfCells method.
11199  * 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]].
11200  * Then it is repeated recursively until either all ids are fetched or no more ids are reachable step by step.
11201  * A negative value in \b arrIn means that it is ignored.
11202  * 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.
11203  * \param [in] seedBg the begin pointer (included) of an array containing the seed of the search zone
11204  * \param [in] seedEnd the end pointer (not included) of an array containing the seed of the search zone
11205  * \param [in] arrIn arr origin array from which the extraction will be done.
11206  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11207  * \param [in] nbOfDepthPeeling the max number of peels requested in search. By default -1, that is to say, no limit.
11208  * \param [out] nbOfDepthPeelingPerformed the number of peels effectively performed. May be different from \a nbOfDepthPeeling
11209  * \return a newly allocated DataArray that stores all ids fetched by the gradually spread process.
11210  * \sa MEDCouplingUMesh::partitionBySpreadZone
11211  */
11212 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed(const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11213 {
11214   nbOfDepthPeelingPerformed=0;
11215   if(!arrIndxIn)
11216     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeed : arrIndxIn input pointer is NULL !");
11217   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11218   if(nbOfTuples<=0)
11219     {
11220       DataArrayInt *ret=DataArrayInt::New(); ret->alloc(0,1);
11221       return ret;
11222     }
11223   //
11224   std::vector<bool> fetched(nbOfTuples,false);
11225   return ComputeSpreadZoneGraduallyFromSeedAlg(fetched,seedBg,seedEnd,arrIn,arrIndxIn,nbOfDepthPeeling,nbOfDepthPeelingPerformed);
11226 }
11227
11228 DataArrayInt *MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg(std::vector<bool>& fetched, const int *seedBg, const int *seedEnd, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn, int nbOfDepthPeeling, int& nbOfDepthPeelingPerformed)
11229 {
11230   nbOfDepthPeelingPerformed=0;
11231   if(!seedBg || !seedEnd || !arrIn || !arrIndxIn)
11232     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeSpreadZoneGraduallyFromSeedAlg : some input pointer is NULL !");
11233   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11234   std::vector<bool> fetched2(nbOfTuples,false);
11235   int i=0;
11236   for(const int *seedElt=seedBg;seedElt!=seedEnd;seedElt++,i++)
11237     {
11238       if(*seedElt>=0 && *seedElt<nbOfTuples)
11239         { fetched[*seedElt]=true; fetched2[*seedElt]=true; }
11240       else
11241         { 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()); }
11242     }
11243   const int *arrInPtr=arrIn->getConstPointer();
11244   const int *arrIndxPtr=arrIndxIn->getConstPointer();
11245   int targetNbOfDepthPeeling=nbOfDepthPeeling!=-1?nbOfDepthPeeling:std::numeric_limits<int>::max();
11246   std::vector<int> idsToFetch1(seedBg,seedEnd);
11247   std::vector<int> idsToFetch2;
11248   std::vector<int> *idsToFetch=&idsToFetch1;
11249   std::vector<int> *idsToFetchOther=&idsToFetch2;
11250   while(!idsToFetch->empty() && nbOfDepthPeelingPerformed<targetNbOfDepthPeeling)
11251     {
11252       for(std::vector<int>::const_iterator it=idsToFetch->begin();it!=idsToFetch->end();it++)
11253         for(const int *it2=arrInPtr+arrIndxPtr[*it];it2!=arrInPtr+arrIndxPtr[*it+1];it2++)
11254           if(!fetched[*it2])
11255             { fetched[*it2]=true; fetched2[*it2]=true; idsToFetchOther->push_back(*it2); }
11256       std::swap(idsToFetch,idsToFetchOther);
11257       idsToFetchOther->clear();
11258       nbOfDepthPeelingPerformed++;
11259     }
11260   int lgth=(int)std::count(fetched2.begin(),fetched2.end(),true);
11261   i=0;
11262   MCAuto<DataArrayInt> ret=DataArrayInt::New(); ret->alloc(lgth,1);
11263   int *retPtr=ret->getPointer();
11264   for(std::vector<bool>::const_iterator it=fetched2.begin();it!=fetched2.end();it++,i++)
11265     if(*it)
11266       *retPtr++=i;
11267   return ret.retn();
11268 }
11269
11270 /*!
11271  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11272  * 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
11273  * cellIds \b in [\b idsOfSelectBg, \b idsOfSelectEnd) a copy coming from the corresponding values in input pair (\b srcArr, \b srcArrIndex).
11274  * This method is an generalization of MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx that performs the same thing but by without building explicitely a result output arrays.
11275  *
11276  * \param [in] start begin of set of ids of the input extraction (included)
11277  * \param [in] end end of set of ids of the input extraction (excluded)
11278  * \param [in] step step of the set of ids in range mode.
11279  * \param [in] arrIn arr origin array from which the extraction will be done.
11280  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11281  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11282  * \param [in] srcArrIndex index array of \b srcArr
11283  * \param [out] arrOut the resulting array
11284  * \param [out] arrIndexOut the index array of the resulting array \b arrOut
11285  * 
11286  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx MEDCouplingUMesh::SetPartOfIndexedArrays
11287  */
11288 void MEDCouplingUMesh::SetPartOfIndexedArraysSlice(int start, int end, int step, const DataArrayInt *arrIn, const DataArrayInt *arrIndxIn,
11289                                                const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex,
11290                                                DataArrayInt* &arrOut, DataArrayInt* &arrIndexOut)
11291 {
11292   if(arrIn==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11293     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSlice : presence of null pointer in input parameter !");
11294   MCAuto<DataArrayInt> arro=DataArrayInt::New();
11295   MCAuto<DataArrayInt> arrIo=DataArrayInt::New();
11296   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11297   int offset=0;
11298   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11299   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11300   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSlice : ");
11301   int it=start;
11302   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11303     {
11304       if(it>=0 && it<nbOfTuples)
11305         offset+=(srcArrIndexPtr[1]-srcArrIndexPtr[0])-(arrIndxInPtr[it+1]-arrIndxInPtr[it]);
11306       else
11307         {
11308           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11309           throw INTERP_KERNEL::Exception(oss.str().c_str());
11310         }
11311     }
11312   srcArrIndexPtr=srcArrIndex->getConstPointer();
11313   arrIo->alloc(nbOfTuples+1,1);
11314   arro->alloc(arrIn->getNumberOfTuples()+offset,1);
11315   const int *arrInPtr=arrIn->getConstPointer();
11316   const int *srcArrPtr=srcArr->getConstPointer();
11317   int *arrIoPtr=arrIo->getPointer(); *arrIoPtr++=0;
11318   int *arroPtr=arro->getPointer();
11319   for(int ii=0;ii<nbOfTuples;ii++,arrIoPtr++)
11320     {
11321       int pos=DataArray::GetPosOfItemGivenBESRelativeNoThrow(ii,start,end,step);
11322       if(pos<0)
11323         {
11324           arroPtr=std::copy(arrInPtr+arrIndxInPtr[ii],arrInPtr+arrIndxInPtr[ii+1],arroPtr);
11325           *arrIoPtr=arrIoPtr[-1]+(arrIndxInPtr[ii+1]-arrIndxInPtr[ii]);
11326         }
11327       else
11328         {
11329           arroPtr=std::copy(srcArrPtr+srcArrIndexPtr[pos],srcArrPtr+srcArrIndexPtr[pos+1],arroPtr);
11330           *arrIoPtr=arrIoPtr[-1]+(srcArrIndexPtr[pos+1]-srcArrIndexPtr[pos]);
11331         }
11332     }
11333   arrOut=arro.retn();
11334   arrIndexOut=arrIo.retn();
11335 }
11336
11337 /*!
11338  * This method works on an input pair (\b arrIn, \b arrIndxIn) where \b arrIn indexes is in \b arrIndxIn.
11339  * This method is an specialization of MEDCouplingUMesh::SetPartOfIndexedArrays in the case of assignement do not modify the index in \b arrIndxIn.
11340  *
11341  * \param [in] start begin of set of ids of the input extraction (included)
11342  * \param [in] end end of set of ids of the input extraction (excluded)
11343  * \param [in] step step of the set of ids in range mode.
11344  * \param [in,out] arrInOut arr origin array from which the extraction will be done.
11345  * \param [in] arrIndxIn is the input index array allowing to walk into \b arrIn
11346  * \param [in] srcArr input array that will be used as source of copy for ids in [\b idsOfSelectBg, \b idsOfSelectEnd)
11347  * \param [in] srcArrIndex index array of \b srcArr
11348  * 
11349  * \sa MEDCouplingUMesh::SetPartOfIndexedArraysSlice MEDCouplingUMesh::SetPartOfIndexedArraysSameIdx
11350  */
11351 void MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice(int start, int end, int step, DataArrayInt *arrInOut, const DataArrayInt *arrIndxIn,
11352                                                       const DataArrayInt *srcArr, const DataArrayInt *srcArrIndex)
11353 {
11354   if(arrInOut==0 || arrIndxIn==0 || srcArr==0 || srcArrIndex==0)
11355     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : presence of null pointer in input parameter !");
11356   int nbOfTuples=arrIndxIn->getNumberOfTuples()-1;
11357   const int *arrIndxInPtr=arrIndxIn->getConstPointer();
11358   const int *srcArrIndexPtr=srcArrIndex->getConstPointer();
11359   int *arrInOutPtr=arrInOut->getPointer();
11360   const int *srcArrPtr=srcArr->getConstPointer();
11361   int nbOfElemsToSet=DataArray::GetNumberOfItemGivenBESRelative(start,end,step,"MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : ");
11362   int it=start;
11363   for(int i=0;i<nbOfElemsToSet;i++,srcArrIndexPtr++,it+=step)
11364     {
11365       if(it>=0 && it<nbOfTuples)
11366         {
11367           if(srcArrIndexPtr[1]-srcArrIndexPtr[0]==arrIndxInPtr[it+1]-arrIndxInPtr[it])
11368             std::copy(srcArrPtr+srcArrIndexPtr[0],srcArrPtr+srcArrIndexPtr[1],arrInOutPtr+arrIndxInPtr[it]);
11369           else
11370             {
11371               std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " id (idsOfSelectBg[" << i << "]) is " << it << " arrIndxIn[id+1]-arrIndxIn[id]!=srcArrIndex[pos+1]-srcArrIndex[pos] !";
11372               throw INTERP_KERNEL::Exception(oss.str().c_str());
11373             }
11374         }
11375       else
11376         {
11377           std::ostringstream oss; oss << "MEDCouplingUMesh::SetPartOfIndexedArraysSameIdxSlice : On pos #" << i << " value is " << it << " not in [0," << nbOfTuples << ") !";
11378           throw INTERP_KERNEL::Exception(oss.str().c_str());
11379         }
11380     }
11381 }
11382
11383 /*!
11384  * \b this is expected to be a mesh fully defined whose spaceDim==meshDim.
11385  * It returns a new allocated mesh having the same mesh dimension and lying on same coordinates.
11386  * The returned mesh contains as poly cells as number of contiguous zone (regarding connectivity).
11387  * A spread contiguous zone is built using poly cells (polyhedra in 3D, polygons in 2D and polyline in 1D).
11388  * The sum of measure field of returned mesh is equal to the sum of measure field of this.
11389  * 
11390  * \return a newly allocated mesh lying on the same coords than \b this with same meshdimension than \b this.
11391  */
11392 MEDCouplingUMesh *MEDCouplingUMesh::buildSpreadZonesWithPoly() const
11393 {
11394   checkFullyDefined();
11395   int mdim=getMeshDimension();
11396   int spaceDim=getSpaceDimension();
11397   if(mdim!=spaceDim)
11398     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension and spacedimension do not match !");
11399   std::vector<DataArrayInt *> partition=partitionBySpreadZone();
11400   std::vector< MCAuto<DataArrayInt> > partitionAuto; partitionAuto.reserve(partition.size());
11401   std::copy(partition.begin(),partition.end(),std::back_insert_iterator<std::vector< MCAuto<DataArrayInt> > >(partitionAuto));
11402   MCAuto<MEDCouplingUMesh> ret=MEDCouplingUMesh::New(getName(),mdim);
11403   ret->setCoords(getCoords());
11404   ret->allocateCells((int)partition.size());
11405   //
11406   for(std::vector<DataArrayInt *>::const_iterator it=partition.begin();it!=partition.end();it++)
11407     {
11408       MCAuto<MEDCouplingUMesh> tmp=static_cast<MEDCouplingUMesh *>(buildPartOfMySelf((*it)->begin(),(*it)->end(),true));
11409       MCAuto<DataArrayInt> cell;
11410       switch(mdim)
11411       {
11412         case 2:
11413           cell=tmp->buildUnionOf2DMesh();
11414           break;
11415         case 3:
11416           cell=tmp->buildUnionOf3DMesh();
11417           break;
11418         default:
11419           throw INTERP_KERNEL::Exception("MEDCouplingUMesh::buildSpreadZonesWithPoly : meshdimension supported are [2,3] ! Not implemented yet for others !");
11420       }
11421
11422       ret->insertNextCell((INTERP_KERNEL::NormalizedCellType)cell->getIJSafe(0,0),cell->getNumberOfTuples()-1,cell->getConstPointer()+1);
11423     }
11424   //
11425   ret->finishInsertingCells();
11426   return ret.retn();
11427 }
11428
11429 /*!
11430  * This method partitions \b this into contiguous zone.
11431  * This method only needs a well defined connectivity. Coordinates are not considered here.
11432  * This method returns a vector of \b newly allocated arrays that the caller has to deal with.
11433  */
11434 std::vector<DataArrayInt *> MEDCouplingUMesh::partitionBySpreadZone() const
11435 {
11436   int nbOfCellsCur=getNumberOfCells();
11437   std::vector<DataArrayInt *> ret;
11438   if(nbOfCellsCur<=0)
11439     return ret;
11440   DataArrayInt *neigh=0,*neighI=0;
11441   computeNeighborsOfCells(neigh,neighI);
11442   MCAuto<DataArrayInt> neighAuto(neigh),neighIAuto(neighI);
11443   std::vector<bool> fetchedCells(nbOfCellsCur,false);
11444   std::vector< MCAuto<DataArrayInt> > ret2;
11445   int seed=0;
11446   while(seed<nbOfCellsCur)
11447     {
11448       int nbOfPeelPerformed=0;
11449       ret2.push_back(ComputeSpreadZoneGraduallyFromSeedAlg(fetchedCells,&seed,&seed+1,neigh,neighI,-1,nbOfPeelPerformed));
11450       seed=(int)std::distance(fetchedCells.begin(),std::find(fetchedCells.begin()+seed,fetchedCells.end(),false));
11451     }
11452   for(std::vector< MCAuto<DataArrayInt> >::iterator it=ret2.begin();it!=ret2.end();it++)
11453     ret.push_back((*it).retn());
11454   return ret;
11455 }
11456
11457 /*!
11458  * This method returns given a distribution of cell type (returned for example by MEDCouplingUMesh::getDistributionOfTypes method and customized after) a
11459  * newly allocated DataArrayInt instance with 2 components ready to be interpreted as input of DataArrayInt::findRangeIdForEachTuple method.
11460  *
11461  * \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.
11462  * \return a newly allocated DataArrayInt to be managed by the caller.
11463  * \throw In case of \a code has not the right format (typically of size 3*n)
11464  */
11465 DataArrayInt *MEDCouplingUMesh::ComputeRangesFromTypeDistribution(const std::vector<int>& code)
11466 {
11467   MCAuto<DataArrayInt> ret=DataArrayInt::New();
11468   std::size_t nb=code.size()/3;
11469   if(code.size()%3!=0)
11470     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::ComputeRangesFromTypeDistribution : invalid input code !");
11471   ret->alloc((int)nb,2);
11472   int *retPtr=ret->getPointer();
11473   for(std::size_t i=0;i<nb;i++,retPtr+=2)
11474     {
11475       retPtr[0]=code[3*i+2];
11476       retPtr[1]=code[3*i+2]+code[3*i+1];
11477     }
11478   return ret.retn();
11479 }
11480
11481 /*!
11482  * This method expects that \a this a 3D mesh (spaceDim=3 and meshDim=3) with all coordinates and connectivities set.
11483  * All cells in \a this are expected to be linear 3D cells.
11484  * This method will split **all** 3D cells in \a this into INTERP_KERNEL::NORM_TETRA4 cells and put them in the returned mesh.
11485  * It leads to an increase to number of cells.
11486  * This method contrary to MEDCouplingUMesh::simplexize can append coordinates in \a this to perform its work.
11487  * The \a nbOfAdditionalPoints returned value informs about it. If > 0, the coordinates array in returned mesh will have \a nbOfAdditionalPoints 
11488  * more tuples (nodes) than in \a this. Anyway, all the nodes in \a this (with the same order) will be in the returned mesh.
11489  *
11490  * \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.
11491  *                      For all other cells, the splitting policy will be ignored. See INTERP_KERNEL::SplittingPolicy for the images.
11492  * \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. 
11493  * \param [out] n2oCells - A new instance of DataArrayInt holding, for each new cell,
11494  *          an id of old cell producing it. The caller is to delete this array using
11495  *         decrRef() as it is no more needed.
11496  * \return MEDCoupling1SGTUMesh * - the mesh containing only INTERP_KERNEL::NORM_TETRA4 cells.
11497  *
11498  * \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
11499  * the policy PLANAR_FACE_6 should be used on a mesh sorted with MEDCoupling1SGTUMesh::sortHexa8EachOther.
11500  * 
11501  * \throw If \a this is not a 3D mesh (spaceDim==3 and meshDim==3).
11502  * \throw If \a this is not fully constituted with linear 3D cells.
11503  * \sa MEDCouplingUMesh::simplexize, MEDCoupling1SGTUMesh::sortHexa8EachOther
11504  */
11505 MEDCoupling1SGTUMesh *MEDCouplingUMesh::tetrahedrize(int policy, DataArrayInt *& n2oCells, int& nbOfAdditionalPoints) const
11506 {
11507   INTERP_KERNEL::SplittingPolicy pol((INTERP_KERNEL::SplittingPolicy)policy);
11508   checkConnectivityFullyDefined();
11509   if(getMeshDimension()!=3 || getSpaceDimension()!=3)
11510     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::tetrahedrize : only available for mesh with meshdim == 3 and spacedim == 3 !");
11511   int nbOfCells(getNumberOfCells()),nbNodes(getNumberOfNodes());
11512   MCAuto<MEDCoupling1SGTUMesh> ret0(MEDCoupling1SGTUMesh::New(getName(),INTERP_KERNEL::NORM_TETRA4));
11513   MCAuto<DataArrayInt> ret(DataArrayInt::New()); ret->alloc(nbOfCells,1);
11514   int *retPt(ret->getPointer());
11515   MCAuto<DataArrayInt> newConn(DataArrayInt::New()); newConn->alloc(0,1);
11516   MCAuto<DataArrayDouble> addPts(DataArrayDouble::New()); addPts->alloc(0,1);
11517   const int *oldc(_nodal_connec->begin());
11518   const int *oldci(_nodal_connec_index->begin());
11519   const double *coords(_coords->begin());
11520   for(int i=0;i<nbOfCells;i++,oldci++,retPt++)
11521     {
11522       std::vector<int> a; std::vector<double> b;
11523       INTERP_KERNEL::SplitIntoTetras(pol,(INTERP_KERNEL::NormalizedCellType)oldc[oldci[0]],oldc+oldci[0]+1,oldc+oldci[1],coords,a,b);
11524       std::size_t nbOfTet(a.size()/4); *retPt=(int)nbOfTet;
11525       const int *aa(&a[0]);
11526       if(!b.empty())
11527         {
11528           for(std::vector<int>::iterator it=a.begin();it!=a.end();it++)
11529             if(*it<0)
11530               *it=(-(*(it))-1+nbNodes);
11531           addPts->insertAtTheEnd(b.begin(),b.end());
11532           nbNodes+=(int)b.size()/3;
11533         }
11534       for(std::size_t j=0;j<nbOfTet;j++,aa+=4)
11535         newConn->insertAtTheEnd(aa,aa+4);
11536     }
11537   if(!addPts->empty())
11538     {
11539       addPts->rearrange(3);
11540       nbOfAdditionalPoints=addPts->getNumberOfTuples();
11541       addPts=DataArrayDouble::Aggregate(getCoords(),addPts);
11542       ret0->setCoords(addPts);
11543     }
11544   else
11545     {
11546       nbOfAdditionalPoints=0;
11547       ret0->setCoords(getCoords());
11548     }
11549   ret0->setNodalConnectivity(newConn);
11550   //
11551   ret->computeOffsetsFull();
11552   n2oCells=ret->buildExplicitArrOfSliceOnScaledArr(0,nbOfCells,1);
11553   return ret0.retn();
11554 }
11555
11556 /*!
11557  * 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). 
11558  *
11559  * \sa MEDCouplingUMesh::split2DCells
11560  */
11561 void MEDCouplingUMesh::split2DCellsLinear(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI)
11562 {
11563   checkConnectivityFullyDefined();
11564   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+subNodesInSeg->getNumberOfTuples());
11565   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11566   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11567   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11568   int prevPosOfCi(ciPtr[0]);
11569   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11570     {
11571       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(0);
11572       *cPtr++=(int)INTERP_KERNEL::NORM_POLYGON; *cPtr++=oldConn[prevPosOfCi+1];
11573       for(int j=0;j<sz;j++)
11574         {
11575           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]);
11576           for(int k=0;k<sz2;k++)
11577             *cPtr++=subPtr[offset2+k];
11578           if(j!=sz-1)
11579             *cPtr++=oldConn[prevPosOfCi+j+2];
11580           deltaSz+=sz2;
11581         }
11582       prevPosOfCi=ciPtr[1];
11583       ciPtr[1]=ciPtr[0]+1+sz+deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11584     }
11585   if(c->end()!=cPtr)
11586     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsLinear : Some of edges to be split are orphan !");
11587   _nodal_connec->decrRef();
11588   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_POLYGON);
11589 }
11590
11591 int InternalAddPoint(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11592 {
11593   if(id!=-1)
11594     return id;
11595   else
11596     {
11597       int ret(nodesCnter++);
11598       double newPt[2];
11599       e->getMiddleOfPoints(coo+2*startId,coo+2*endId,newPt);
11600       addCoo.insertAtTheEnd(newPt,newPt+2);
11601       return ret;
11602     }
11603 }
11604
11605 int InternalAddPointOriented(const INTERP_KERNEL::Edge *e, int id, const double *coo, int startId, int endId, DataArrayDouble& addCoo, int& nodesCnter)
11606 {
11607   if(id!=-1)
11608     return id;
11609   else
11610     {
11611       int ret(nodesCnter++);
11612       double newPt[2];
11613       e->getMiddleOfPointsOriented(coo+2*startId,coo+2*endId,newPt);
11614       addCoo.insertAtTheEnd(newPt,newPt+2);
11615       return ret;
11616     }
11617 }
11618
11619
11620 /// @cond INTERNAL
11621
11622 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)
11623 {
11624   int tmp[3];
11625   int trueStart(start>=0?start:nbOfEdges+start);
11626   tmp[0]=linOrArc?(int)INTERP_KERNEL::NORM_QPOLYG:(int)INTERP_KERNEL::NORM_POLYGON; tmp[1]=connBg[trueStart]; tmp[2]=connBg[stp];
11627   newConnOfCell->insertAtTheEnd(tmp,tmp+3);
11628   if(linOrArc)
11629     {
11630       if(stp-start>1)
11631         {
11632           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11633           InternalAddPointOriented(e,-1,coords,tmp[1],tmp[2],*appendedCoords,tmp2);
11634           middles.push_back(tmp3+offset);
11635         }
11636       else
11637         middles.push_back(connBg[trueStart+nbOfEdges]);
11638     }
11639 }
11640
11641 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)
11642 {
11643   int tmpSrt(newConnOfCell->back()),tmpEnd(connBg[stp]);
11644   newConnOfCell->pushBackSilent(tmpEnd);
11645   if(linOrArc)
11646     {
11647       if(stp-start>1)
11648         {
11649           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11650           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11651           middles.push_back(tmp3+offset);
11652         }
11653       else
11654         middles.push_back(connBg[start+nbOfEdges]);
11655     }
11656 }
11657
11658 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)
11659 {
11660   // only the quadratic point to deal with:
11661   if(linOrArc)
11662     {
11663       if(stp-start>1)
11664         {
11665           int tmpSrt(connBg[start]),tmpEnd(connBg[stp]);
11666           int tmp2(0),tmp3(appendedCoords->getNumberOfTuples()/2);
11667           InternalAddPointOriented(e,-1,coords,tmpSrt,tmpEnd,*appendedCoords,tmp2);
11668           middles.push_back(tmp3+offset);
11669         }
11670       else
11671         middles.push_back(connBg[start+nbOfEdges]);
11672     }
11673 }
11674
11675 /// @endcond
11676
11677 /*!
11678  * 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 ) .
11679  * \a appendedCoords is a DataArrayDouble instance with number of components equal to one (even if the items are pushed by pair).
11680  */
11681 bool MEDCouplingUMesh::Colinearize2DCell(const double *coords, const int *connBg, const int *connEnd, int offset, DataArrayInt *newConnOfCell, DataArrayDouble *appendedCoords)
11682 {
11683   std::size_t sz(std::distance(connBg,connEnd));
11684   if(sz<3)//3 because 2+1(for the cell type) and 2 is the minimal number of edges of 2D cell.
11685     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::Colinearize2DCell : the input cell has invalid format !");
11686   sz--;
11687   INTERP_KERNEL::AutoPtr<int> tmpConn(new int[sz]);
11688   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)connBg[0]));
11689   unsigned nbs(cm.getNumberOfSons2(connBg+1,sz));
11690   unsigned nbOfHit(0); // number of fusions operated
11691   int posBaseElt(0),posEndElt(0),nbOfTurn(0);
11692   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
11693   INTERP_KERNEL::NormalizedCellType typeOfSon;
11694   std::vector<int> middles;
11695   bool ret(false);
11696   for(;(nbOfTurn+nbOfHit)<nbs;nbOfTurn++)
11697     {
11698       cm.fillSonCellNodalConnectivity2(posBaseElt,connBg+1,sz,tmpConn,typeOfSon);
11699       std::map<MCAuto<INTERP_KERNEL::Node>,int> m;
11700       INTERP_KERNEL::Edge *e(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11701       posEndElt = posBaseElt+1;
11702
11703       // Look backward first: are the final edges of the cells colinear with the first ones?
11704       // This initializes posBaseElt.
11705       if(nbOfTurn==0)
11706         {
11707           for(unsigned i=1;i<nbs && nbOfHit<maxNbOfHit;i++) // 2nd condition is to avoid ending with a cell wih one single edge
11708             {
11709               cm.fillSonCellNodalConnectivity2(nbs-i,connBg+1,sz,tmpConn,typeOfSon);
11710               INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11711               INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11712               bool isColinear=eint->areColinears();
11713               if(isColinear)
11714                 {
11715                   nbOfHit++;
11716                   posBaseElt--;
11717                   ret=true;
11718                 }
11719               delete eint;
11720               eCand->decrRef();
11721               if(!isColinear)
11722                 break;
11723             }
11724         }
11725       // Now move forward:
11726       const unsigned fwdStart = (nbOfTurn == 0 ? 0 : posBaseElt);  // the first element to be inspected going forward
11727       for(unsigned j=fwdStart+1;j<nbs && nbOfHit<maxNbOfHit;j++)  // 2nd condition is to avoid ending with a cell wih one single edge
11728         {
11729           cm.fillSonCellNodalConnectivity2((int)j,connBg+1,sz,tmpConn,typeOfSon); // get edge #j's connectivity
11730           INTERP_KERNEL::Edge *eCand(MEDCouplingUMeshBuildQPFromEdge2(typeOfSon,tmpConn,coords,m));
11731           INTERP_KERNEL::EdgeIntersector *eint(INTERP_KERNEL::Edge::BuildIntersectorWith(e,eCand));
11732           bool isColinear(eint->areColinears());
11733           if(isColinear)
11734             {
11735               nbOfHit++;
11736               posEndElt++;
11737               ret=true;
11738             }
11739           delete eint;
11740           eCand->decrRef();
11741           if(!isColinear)
11742               break;
11743         }
11744       //push [posBaseElt,posEndElt) in newConnOfCell using e
11745       // 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!
11746       if(nbOfTurn==0)
11747         // at the begining of the connectivity (insert type)
11748         EnterTheResultOf2DCellFirst(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11749       else if((nbOfHit+nbOfTurn) != (nbs-1))
11750         // in the middle
11751         EnterTheResultOf2DCellMiddle(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11752       if ((nbOfHit+nbOfTurn) == (nbs-1))
11753         // at the end (only quad points to deal with)
11754         EnterTheResultOf2DCellEnd(e,posBaseElt,posEndElt,(int)nbs,cm.isQuadratic(),coords,connBg+1,offset,newConnOfCell,appendedCoords,middles);
11755       posBaseElt=posEndElt;
11756       e->decrRef();
11757     }
11758   if(!middles.empty())
11759     newConnOfCell->insertAtTheEnd(middles.begin(),middles.end());
11760   return ret;
11761 }
11762
11763 /*!
11764  * It is the quadratic part of MEDCouplingUMesh::split2DCells. Here some additionnal nodes can be added at the end of coordinates array object.
11765  *
11766  * \return  int - the number of new nodes created.
11767  * \sa MEDCouplingUMesh::split2DCells
11768  */
11769 int MEDCouplingUMesh::split2DCellsQuadratic(const DataArrayInt *desc, const DataArrayInt *descI, const DataArrayInt *subNodesInSeg, const DataArrayInt *subNodesInSegI, const DataArrayInt *mid, const DataArrayInt *midI)
11770 {
11771   checkConsistencyLight();
11772   int ncells(getNumberOfCells()),lgthToReach(getNodalConnectivityArrayLen()+2*subNodesInSeg->getNumberOfTuples()),nodesCnt(getNumberOfNodes());
11773   MCAuto<DataArrayInt> c(DataArrayInt::New()); c->alloc((std::size_t)lgthToReach);
11774   MCAuto<DataArrayDouble> addCoo(DataArrayDouble::New()); addCoo->alloc(0,1);
11775   const int *subPtr(subNodesInSeg->begin()),*subIPtr(subNodesInSegI->begin()),*descPtr(desc->begin()),*descIPtr(descI->begin()),*oldConn(getNodalConnectivity()->begin());
11776   const int *midPtr(mid->begin()),*midIPtr(midI->begin());
11777   const double *oldCoordsPtr(getCoords()->begin());
11778   int *cPtr(c->getPointer()),*ciPtr(getNodalConnectivityIndex()->getPointer());
11779   int prevPosOfCi(ciPtr[0]);
11780   for(int i=0;i<ncells;i++,ciPtr++,descIPtr++)
11781     {
11782       int offset(descIPtr[0]),sz(descIPtr[1]-descIPtr[0]),deltaSz(sz);
11783       for(int j=0;j<sz;j++)
11784         { int sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]); deltaSz+=sz2; }
11785       *cPtr++=(int)INTERP_KERNEL::NORM_QPOLYG; cPtr[0]=oldConn[prevPosOfCi+1];
11786       for(int j=0;j<sz;j++)//loop over subedges of oldConn
11787         {
11788           int offset2(subIPtr[descPtr[offset+j]]),sz2(subIPtr[descPtr[offset+j]+1]-subIPtr[descPtr[offset+j]]),offset3(midIPtr[descPtr[offset+j]]);
11789           if(sz2==0)
11790             {
11791               if(j<sz-1)
11792                 cPtr[1]=oldConn[prevPosOfCi+2+j];
11793               cPtr[deltaSz]=oldConn[prevPosOfCi+1+j+sz]; cPtr++;
11794               continue;
11795             }
11796           std::vector<INTERP_KERNEL::Node *> ns(3);
11797           ns[0]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+j]+1]);
11798           ns[1]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+(1+j)%sz]+1]);
11799           ns[2]=new INTERP_KERNEL::Node(oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]],oldCoordsPtr[2*oldConn[prevPosOfCi+1+sz+j]+1]);
11800           MCAuto<INTERP_KERNEL::Edge> e(INTERP_KERNEL::QuadraticPolygon::BuildArcCircleEdge(ns));
11801           for(int k=0;k<sz2;k++)//loop over subsplit of current subedge
11802             {
11803               cPtr[1]=subPtr[offset2+k];
11804               cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+k],oldCoordsPtr,cPtr[0],cPtr[1],*addCoo,nodesCnt); cPtr++;
11805             }
11806           int tmpEnd(oldConn[prevPosOfCi+1+(j+1)%sz]);
11807           if(j!=sz-1)
11808             { cPtr[1]=tmpEnd; }
11809           cPtr[deltaSz]=InternalAddPoint(e,midPtr[offset3+sz2],oldCoordsPtr,cPtr[0],tmpEnd,*addCoo,nodesCnt); cPtr++;
11810         }
11811       prevPosOfCi=ciPtr[1]; cPtr+=deltaSz;
11812       ciPtr[1]=ciPtr[0]+1+2*deltaSz;//sz==old nb of nodes because (nb of subedges=nb of nodes for polygons)
11813     }
11814   if(c->end()!=cPtr)
11815     throw INTERP_KERNEL::Exception("MEDCouplingUMesh::split2DCellsQuadratic : Some of edges to be split are orphan !");
11816   _nodal_connec->decrRef();
11817   _nodal_connec=c.retn(); _types.clear(); _types.insert(INTERP_KERNEL::NORM_QPOLYG);
11818   addCoo->rearrange(2);
11819   MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(getCoords(),addCoo));//info are copied from getCoords() by using Aggregate
11820   setCoords(coo);
11821   return addCoo->getNumberOfTuples();
11822 }
11823
11824 void MEDCouplingUMesh::ComputeAllTypesInternal(std::set<INTERP_KERNEL::NormalizedCellType>& types, const DataArrayInt *nodalConnec, const DataArrayInt *nodalConnecIndex)
11825 {
11826   if(nodalConnec && nodalConnecIndex)
11827     {
11828       types.clear();
11829       const int *conn(nodalConnec->getConstPointer()),*connIndex(nodalConnecIndex->getConstPointer());
11830       int nbOfElem(nodalConnecIndex->getNbOfElems()-1);
11831       if(nbOfElem>0)
11832         for(const int *pt=connIndex;pt!=connIndex+nbOfElem;pt++)
11833           types.insert((INTERP_KERNEL::NormalizedCellType)conn[*pt]);
11834     }
11835 }
11836
11837 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),
11838     _own_cell(true),_cell_id(-1),_nb_cell(0)
11839 {
11840   if(mesh)
11841     {
11842       mesh->incrRef();
11843       _nb_cell=mesh->getNumberOfCells();
11844     }
11845 }
11846
11847 MEDCouplingUMeshCellIterator::~MEDCouplingUMeshCellIterator()
11848 {
11849   if(_mesh)
11850     _mesh->decrRef();
11851   if(_own_cell)
11852     delete _cell;
11853 }
11854
11855 MEDCouplingUMeshCellIterator::MEDCouplingUMeshCellIterator(MEDCouplingUMesh *mesh, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_cell(itc),
11856     _own_cell(false),_cell_id(bg-1),
11857     _nb_cell(end)
11858 {
11859   if(mesh)
11860     mesh->incrRef();
11861 }
11862
11863 MEDCouplingUMeshCell *MEDCouplingUMeshCellIterator::nextt()
11864 {
11865   _cell_id++;
11866   if(_cell_id<_nb_cell)
11867     {
11868       _cell->next();
11869       return _cell;
11870     }
11871   else
11872     return 0;
11873 }
11874
11875 MEDCouplingUMeshCellByTypeEntry::MEDCouplingUMeshCellByTypeEntry(MEDCouplingUMesh *mesh):_mesh(mesh)
11876 {
11877   if(_mesh)
11878     _mesh->incrRef();
11879 }
11880
11881 MEDCouplingUMeshCellByTypeIterator *MEDCouplingUMeshCellByTypeEntry::iterator()
11882 {
11883   return new MEDCouplingUMeshCellByTypeIterator(_mesh);
11884 }
11885
11886 MEDCouplingUMeshCellByTypeEntry::~MEDCouplingUMeshCellByTypeEntry()
11887 {
11888   if(_mesh)
11889     _mesh->decrRef();
11890 }
11891
11892 MEDCouplingUMeshCellEntry::MEDCouplingUMeshCellEntry(MEDCouplingUMesh *mesh,  INTERP_KERNEL::NormalizedCellType type, MEDCouplingUMeshCell *itc, int bg, int end):_mesh(mesh),_type(type),
11893     _itc(itc),
11894     _bg(bg),_end(end)
11895 {
11896   if(_mesh)
11897     _mesh->incrRef();
11898 }
11899
11900 MEDCouplingUMeshCellEntry::~MEDCouplingUMeshCellEntry()
11901 {
11902   if(_mesh)
11903     _mesh->decrRef();
11904 }
11905
11906 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCellEntry::getType() const
11907 {
11908   return _type;
11909 }
11910
11911 int MEDCouplingUMeshCellEntry::getNumberOfElems() const
11912 {
11913   return _end-_bg;
11914 }
11915
11916 MEDCouplingUMeshCellIterator *MEDCouplingUMeshCellEntry::iterator()
11917 {
11918   return new MEDCouplingUMeshCellIterator(_mesh,_itc,_bg,_end);
11919 }
11920
11921 MEDCouplingUMeshCellByTypeIterator::MEDCouplingUMeshCellByTypeIterator(MEDCouplingUMesh *mesh):_mesh(mesh),_cell(new MEDCouplingUMeshCell(mesh)),_cell_id(0),_nb_cell(0)
11922 {
11923   if(mesh)
11924     {
11925       mesh->incrRef();
11926       _nb_cell=mesh->getNumberOfCells();
11927     }
11928 }
11929
11930 MEDCouplingUMeshCellByTypeIterator::~MEDCouplingUMeshCellByTypeIterator()
11931 {
11932   if(_mesh)
11933     _mesh->decrRef();
11934   delete _cell;
11935 }
11936
11937 MEDCouplingUMeshCellEntry *MEDCouplingUMeshCellByTypeIterator::nextt()
11938 {
11939   const int *c=_mesh->getNodalConnectivity()->getConstPointer();
11940   const int *ci=_mesh->getNodalConnectivityIndex()->getConstPointer();
11941   if(_cell_id<_nb_cell)
11942     {
11943       INTERP_KERNEL::NormalizedCellType type=(INTERP_KERNEL::NormalizedCellType)c[ci[_cell_id]];
11944       int nbOfElems=(int)std::distance(ci+_cell_id,std::find_if(ci+_cell_id,ci+_nb_cell,MEDCouplingImpl::ConnReader(c,type)));
11945       int startId=_cell_id;
11946       _cell_id+=nbOfElems;
11947       return new MEDCouplingUMeshCellEntry(_mesh,type,_cell,startId,_cell_id);
11948     }
11949   else
11950     return 0;
11951 }
11952
11953 MEDCouplingUMeshCell::MEDCouplingUMeshCell(MEDCouplingUMesh *mesh):_conn(0),_conn_indx(0),_conn_lgth(NOTICABLE_FIRST_VAL)
11954 {
11955   if(mesh)
11956     {
11957       _conn=mesh->getNodalConnectivity()->getPointer();
11958       _conn_indx=mesh->getNodalConnectivityIndex()->getPointer();
11959     }
11960 }
11961
11962 void MEDCouplingUMeshCell::next()
11963 {
11964   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11965     {
11966       _conn+=_conn_lgth;
11967       _conn_indx++;
11968     }
11969   _conn_lgth=_conn_indx[1]-_conn_indx[0];
11970 }
11971
11972 std::string MEDCouplingUMeshCell::repr() const
11973 {
11974   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11975     {
11976       std::ostringstream oss; oss << "Cell Type " << INTERP_KERNEL::CellModel::GetCellModel((INTERP_KERNEL::NormalizedCellType)_conn[0]).getRepr();
11977       oss << " : ";
11978       std::copy(_conn+1,_conn+_conn_lgth,std::ostream_iterator<int>(oss," "));
11979       return oss.str();
11980     }
11981   else
11982     return std::string("MEDCouplingUMeshCell::repr : Invalid pos");
11983 }
11984
11985 INTERP_KERNEL::NormalizedCellType MEDCouplingUMeshCell::getType() const
11986 {
11987   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11988     return (INTERP_KERNEL::NormalizedCellType)_conn[0];
11989   else
11990     return INTERP_KERNEL::NORM_ERROR;
11991 }
11992
11993 const int *MEDCouplingUMeshCell::getAllConn(int& lgth) const
11994 {
11995   lgth=_conn_lgth;
11996   if(_conn_lgth!=NOTICABLE_FIRST_VAL)
11997     return _conn;
11998   else
11999     return 0;
12000 }